♻️ Move most of models to the Shared package

This commit is contained in:
2025-07-06 22:34:52 +08:00
parent cb4acbb3fc
commit 65450e8511
170 changed files with 679 additions and 101121 deletions

View File

@ -0,0 +1,95 @@
using DysonNetwork.Shared.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using NodaTime;
namespace DysonNetwork.Pass.Data;
public abstract class ModelBase
{
public Instant CreatedAt { get; set; }
public Instant UpdatedAt { get; set; }
public Instant? DeletedAt { get; set; }
}
public class AppDatabase(
DbContextOptions<AppDatabase> options,
IConfiguration configuration
) : DbContext(options)
{
public DbSet<PermissionNode> PermissionNodes { get; set; }
public DbSet<PermissionGroup> PermissionGroups { get; set; }
public DbSet<PermissionGroupMember> PermissionGroupMembers { get; set; }
public DbSet<Account> Accounts { get; set; }
public DbSet<AccountConnection> AccountConnections { get; set; }
public DbSet<Profile> AccountProfiles { get; set; }
public DbSet<AccountContact> AccountContacts { get; set; }
public DbSet<AccountAuthFactor> AccountAuthFactors { get; set; }
public DbSet<Relationship> AccountRelationships { get; set; }
public DbSet<Session> AuthSessions { get; set; }
public DbSet<Challenge> AuthChallenges { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql(
configuration.GetConnectionString("App"),
opt => opt
.UseNodaTime()
).UseSnakeCaseNamingConvention();
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<PermissionGroupMember>()
.HasKey(pg => new { pg.GroupId, pg.Actor });
modelBuilder.Entity<Relationship>()
.HasKey(r => new { FromAccountId = r.AccountId, ToAccountId = r.RelatedId });
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
var now = SystemClock.Instance.GetCurrentInstant();
foreach (var entry in ChangeTracker.Entries<ModelBase>())
{
if (entry.State == EntityState.Added)
{
entry.Entity.CreatedAt = now;
entry.Entity.UpdatedAt = now;
}
else if (entry.State == EntityState.Modified)
{
entry.Entity.UpdatedAt = now;
}
else if (entry.State == EntityState.Deleted)
{
entry.State = EntityState.Modified;
entry.Entity.DeletedAt = now;
}
}
return await base.SaveChangesAsync(cancellationToken);
}
}
public class AppDatabaseFactory : IDesignTimeDbContextFactory<AppDatabase>
{
public AppDatabase CreateDbContext(string[] args)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var optionsBuilder = new DbContextOptionsBuilder<AppDatabase>();
return new AppDatabase(optionsBuilder.Options, configuration);
}
}

View File

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EFCore.NamingConventions" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.6" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime" Version="9.0.4" />
<PackageReference Include="StackExchange.Redis" Version="2.8.41" />
<PackageReference Include="StackExchange.Redis.Extensions.AspNetCore" Version="11.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DysonNetwork.Shared\DysonNetwork.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore">
<HintPath>..\..\..\..\..\..\opt\homebrew\Cellar\dotnet\9.0.6\libexec\shared\Microsoft.AspNetCore.App\9.0.6\Microsoft.AspNetCore.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,28 @@
using DysonNetwork.Pass.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddDbContext<AppDatabase>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("App")));
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseAuthorization();
app.MapControllers();
// Run database migrations
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDatabase>();
await db.Database.MigrateAsync();
}
app.Run();

View File

@ -0,0 +1,11 @@
{
"ConnectionStrings": {
"App": "Host=localhost;Port=5432;Database=dyson_network_pass;Username=postgres;Password=password"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -11,12 +11,18 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="Grpc.Net.Client" Version="2.65.0" /> <PackageReference Include="Grpc.Net.Client" Version="2.65.0" />
<PackageReference Include="Google.Protobuf" Version="3.27.2" /> <PackageReference Include="Google.Protobuf" Version="3.27.2" />
<PackageReference Include="Grpc.Tools" Version="2.65.0"> <PackageReference Include="Grpc.Tools" Version="2.65.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" />
<PackageReference Include="NetTopologySuite" Version="2.6.0" />
<PackageReference Include="NodaTime" Version="3.2.2" />
<PackageReference Include="Otp.NET" Version="1.4.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.41" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,14 +1,11 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Sphere.Permission;
using DysonNetwork.Sphere.Storage;
using DysonNetwork.Sphere.Wallet;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
using OtpNet; using OtpNet;
namespace DysonNetwork.Sphere.Account; namespace DysonNetwork.Shared.Models;
[Index(nameof(Name), IsUnique = true)] [Index(nameof(Name), IsUnique = true)]
public class Account : ModelBase public class Account : ModelBase
@ -26,8 +23,8 @@ public class Account : ModelBase
[JsonIgnore] public ICollection<AccountAuthFactor> AuthFactors { get; set; } = new List<AccountAuthFactor>(); [JsonIgnore] public ICollection<AccountAuthFactor> AuthFactors { get; set; } = new List<AccountAuthFactor>();
[JsonIgnore] public ICollection<AccountConnection> Connections { get; set; } = new List<AccountConnection>(); [JsonIgnore] public ICollection<AccountConnection> Connections { get; set; } = new List<AccountConnection>();
[JsonIgnore] public ICollection<Auth.Session> Sessions { get; set; } = new List<Auth.Session>(); [JsonIgnore] public ICollection<Session> Sessions { get; set; } = new List<Session>();
[JsonIgnore] public ICollection<Auth.Challenge> Challenges { get; set; } = new List<Auth.Challenge>(); [JsonIgnore] public ICollection<Challenge> Challenges { get; set; } = new List<Challenge>();
[JsonIgnore] public ICollection<Relationship> OutgoingRelationships { get; set; } = new List<Relationship>(); [JsonIgnore] public ICollection<Relationship> OutgoingRelationships { get; set; } = new List<Relationship>();
[JsonIgnore] public ICollection<Relationship> IncomingRelationships { get; set; } = new List<Relationship>(); [JsonIgnore] public ICollection<Relationship> IncomingRelationships { get; set; } = new List<Relationship>();

View File

@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Account; namespace DysonNetwork.Shared.Models;
public enum StatusAttitude public enum StatusAttitude
{ {
@ -23,7 +23,7 @@ public class Status : ModelBase
public Instant? ClearedAt { get; set; } public Instant? ClearedAt { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
} }
public enum CheckInResultLevel public enum CheckInResultLevel
@ -44,7 +44,7 @@ public class CheckInResult : ModelBase
[Column(TypeName = "jsonb")] public ICollection<FortuneTip> Tips { get; set; } = new List<FortuneTip>(); [Column(TypeName = "jsonb")] public ICollection<FortuneTip> Tips { get; set; } = new List<FortuneTip>();
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
} }
public class FortuneTip public class FortuneTip

View File

@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Point = NetTopologySuite.Geometries.Point; using Point = NetTopologySuite.Geometries.Point;
namespace DysonNetwork.Sphere.Account; namespace DysonNetwork.Shared.Models;
public abstract class ActionLogType public abstract class ActionLogType
{ {
@ -53,6 +53,6 @@ public class ActionLog : ModelBase
public Point? Location { get; set; } public Point? Location { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
public Guid? SessionId { get; set; } public Guid? SessionId { get; set; }
} }

View File

@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Account; namespace DysonNetwork.Shared.Models;
public class Badge : ModelBase public class Badge : ModelBase
{ {
@ -16,7 +16,7 @@ public class Badge : ModelBase
public Instant? ExpiredAt { get; set; } public Instant? ExpiredAt { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
[JsonIgnore] public Account Account { get; set; } = null!; [JsonIgnore] public Shared.Models.Account Account { get; set; } = null!;
public BadgeReferenceObject ToReference() public BadgeReferenceObject ToReference()
{ {

View File

@ -1,10 +1,9 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Sphere.Storage;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Chat; namespace DysonNetwork.Shared.Models;
public enum ChatRoomType public enum ChatRoomType
{ {
@ -31,7 +30,7 @@ public class ChatRoom : ModelBase, IIdentifiedResource
[JsonIgnore] public ICollection<ChatMember> Members { get; set; } = new List<ChatMember>(); [JsonIgnore] public ICollection<ChatMember> Members { get; set; } = new List<ChatMember>();
public Guid? RealmId { get; set; } public Guid? RealmId { get; set; }
public Realm.Realm? Realm { get; set; } public Shared.Models.Realm? Realm { get; set; }
[NotMapped] [NotMapped]
[JsonPropertyName("members")] [JsonPropertyName("members")]
@ -73,7 +72,7 @@ public class ChatMember : ModelBase
public Guid ChatRoomId { get; set; } public Guid ChatRoomId { get; set; }
public ChatRoom ChatRoom { get; set; } = null!; public ChatRoom ChatRoom { get; set; } = null!;
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account.Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
[MaxLength(1024)] public string? Nick { get; set; } [MaxLength(1024)] public string? Nick { get; set; }
@ -105,7 +104,7 @@ public class ChatMemberTransmissionObject : ModelBase
public Guid Id { get; set; } public Guid Id { get; set; }
public Guid ChatRoomId { get; set; } public Guid ChatRoomId { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account.Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
[MaxLength(1024)] public string? Nick { get; set; } [MaxLength(1024)] public string? Nick { get; set; }

View File

@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Storage; namespace DysonNetwork.Shared.Models;
public class RemoteStorageConfig public class RemoteStorageConfig
{ {
@ -20,6 +20,59 @@ public class RemoteStorageConfig
public string? AccessProxy { get; set; } public string? AccessProxy { get; set; }
} }
/// <summary>
/// Common interface for cloud file entities that can be used in file operations.
/// This interface exposes the essential properties needed for file operations
/// and is implemented by both CloudFile and CloudFileReferenceObject.
/// </summary>
public interface ICloudFile
{
public Instant CreatedAt { get; }
public Instant UpdatedAt { get; }
public Instant? DeletedAt { get; }
/// <summary>
/// Gets the unique identifier of the cloud file.
/// </summary>
string Id { get; }
/// <summary>
/// Gets the name of the cloud file.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the file metadata dictionary.
/// </summary>
Dictionary<string, object>? FileMeta { get; }
/// <summary>
/// Gets the user metadata dictionary.
/// </summary>
Dictionary<string, object>? UserMeta { get; }
/// <summary>
/// Gets the MIME type of the file.
/// </summary>
string? MimeType { get; }
/// <summary>
/// Gets the hash of the file content.
/// </summary>
string? Hash { get; }
/// <summary>
/// Gets the size of the file in bytes.
/// </summary>
long Size { get; }
/// <summary>
/// Gets whether the file has a compressed version available.
/// </summary>
bool HasCompression { get; }
}
/// <summary> /// <summary>
/// The class that used in jsonb columns which referenced the cloud file. /// The class that used in jsonb columns which referenced the cloud file.
/// The aim of this class is to store some properties that won't change to a file to reduce the database load. /// The aim of this class is to store some properties that won't change to a file to reduce the database load.
@ -74,7 +127,7 @@ public class CloudFile : ModelBase, ICloudFile, IIdentifiedResource
[MaxLength(4096)] [MaxLength(4096)]
public string? StorageUrl { get; set; } public string? StorageUrl { get; set; }
[JsonIgnore] public Account.Account Account { get; set; } = null!; [JsonIgnore] public Shared.Models.Account Account { get; set; } = null!;
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public CloudFileReferenceObject ToReferenceObject() public CloudFileReferenceObject ToReferenceObject()

View File

@ -1,11 +1,9 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Storage;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Developer; namespace DysonNetwork.Shared.Models;
public enum CustomAppStatus public enum CustomAppStatus
{ {
@ -33,7 +31,7 @@ public class CustomApp : ModelBase, IIdentifiedResource
[JsonIgnore] public ICollection<CustomAppSecret> Secrets { get; set; } = new List<CustomAppSecret>(); [JsonIgnore] public ICollection<CustomAppSecret> Secrets { get; set; } = new List<CustomAppSecret>();
public Guid PublisherId { get; set; } public Guid PublisherId { get; set; }
public Publisher.Publisher Developer { get; set; } = null!; public Publisher Developer { get; set; } = null!;
[NotMapped] public string ResourceIdentifier => "custom-app/" + Id; [NotMapped] public string ResourceIdentifier => "custom-app/" + Id;
} }

View File

@ -1,11 +1,9 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Chat; namespace DysonNetwork.Shared.Models;
public class Message : ModelBase, IIdentifiedResource public class Message : ModelBase, IIdentifiedResource
{ {

View File

@ -0,0 +1,15 @@
using NodaTime;
namespace DysonNetwork.Shared.Models;
public interface IIdentifiedResource
{
public string ResourceIdentifier { get; }
}
public abstract class ModelBase
{
public Instant CreatedAt { get; set; }
public Instant UpdatedAt { get; set; }
public Instant? DeletedAt { get; set; }
}

View File

@ -4,7 +4,7 @@ using System.Text.Json.Serialization;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Account; namespace DysonNetwork.Shared.Models;
public class Notification : ModelBase public class Notification : ModelBase
{ {
@ -18,7 +18,7 @@ public class Notification : ModelBase
public Instant? ViewedAt { get; set; } public Instant? ViewedAt { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
[JsonIgnore] public Account Account { get; set; } = null!; [JsonIgnore] public Shared.Models.Account Account { get; set; } = null!;
} }
public enum NotificationPushProvider public enum NotificationPushProvider
@ -37,5 +37,5 @@ public class NotificationPushSubscription : ModelBase
public Instant? LastUsedAt { get; set; } public Instant? LastUsedAt { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
[JsonIgnore] public Account Account { get; set; } = null!; [JsonIgnore] public Shared.Models.Account Account { get; set; } = null!;
} }

View File

@ -1,9 +1,8 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using DysonNetwork.Sphere.Developer;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Wallet; namespace DysonNetwork.Shared.Models;
public class WalletCurrency public class WalletCurrency
{ {
@ -32,7 +31,7 @@ public class Order : ModelBase
public Instant ExpiredAt { get; set; } public Instant ExpiredAt { get; set; }
public Guid? PayeeWalletId { get; set; } public Guid? PayeeWalletId { get; set; }
public Wallet? PayeeWallet { get; set; } = null!; public Shared.Models.Wallet? PayeeWallet { get; set; } = null!;
public Guid? TransactionId { get; set; } public Guid? TransactionId { get; set; }
public Transaction? Transaction { get; set; } public Transaction? Transaction { get; set; }
public Guid? IssuerAppId { get; set; } public Guid? IssuerAppId { get; set; }
@ -56,8 +55,8 @@ public class Transaction : ModelBase
// When the payer is null, it's pay from the system // When the payer is null, it's pay from the system
public Guid? PayerWalletId { get; set; } public Guid? PayerWalletId { get; set; }
public Wallet? PayerWallet { get; set; } public Shared.Models.Wallet? PayerWallet { get; set; }
// When the payee is null, it's pay for the system // When the payee is null, it's pay for the system
public Guid? PayeeWalletId { get; set; } public Guid? PayeeWalletId { get; set; }
public Wallet? PayeeWallet { get; set; } public Shared.Models.Wallet? PayeeWallet { get; set; }
} }

View File

@ -5,7 +5,7 @@ using System.Text.Json.Serialization;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Permission; namespace DysonNetwork.Shared.Models;
/// The permission node model provides the infrastructure of permission control in Dyson Network. /// The permission node model provides the infrastructure of permission control in Dyson Network.
/// It based on the ABAC permission model. /// It based on the ABAC permission model.

View File

@ -1,12 +1,10 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Sphere.Post;
using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Publisher; namespace DysonNetwork.Shared.Models;
public enum PublisherType public enum PublisherType
{ {
@ -30,10 +28,8 @@ public class Publisher : ModelBase, IIdentifiedResource
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Picture { get; set; } [Column(TypeName = "jsonb")] public CloudFileReferenceObject? Picture { get; set; }
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Background { get; set; } [Column(TypeName = "jsonb")] public CloudFileReferenceObject? Background { get; set; }
[Column(TypeName = "jsonb")] public Account.VerificationMark? Verification { get; set; } [Column(TypeName = "jsonb")] public VerificationMark? Verification { get; set; }
[JsonIgnore] public ICollection<Post.Post> Posts { get; set; } = new List<Post.Post>();
[JsonIgnore] public ICollection<PostCollection> Collections { get; set; } = new List<PostCollection>();
[JsonIgnore] public ICollection<PublisherMember> Members { get; set; } = new List<PublisherMember>(); [JsonIgnore] public ICollection<PublisherMember> Members { get; set; } = new List<PublisherMember>();
[JsonIgnore] public ICollection<PublisherFeature> Features { get; set; } = new List<PublisherFeature>(); [JsonIgnore] public ICollection<PublisherFeature> Features { get; set; } = new List<PublisherFeature>();
@ -41,9 +37,9 @@ public class Publisher : ModelBase, IIdentifiedResource
public ICollection<PublisherSubscription> Subscriptions { get; set; } = new List<PublisherSubscription>(); public ICollection<PublisherSubscription> Subscriptions { get; set; } = new List<PublisherSubscription>();
public Guid? AccountId { get; set; } public Guid? AccountId { get; set; }
public Account.Account? Account { get; set; } public Shared.Models.Account? Account { get; set; }
public Guid? RealmId { get; set; } public Guid? RealmId { get; set; }
[JsonIgnore] public Realm.Realm? Realm { get; set; } [JsonIgnore] public Realm? Realm { get; set; }
public string ResourceIdentifier => $"publisher/{Id}"; public string ResourceIdentifier => $"publisher/{Id}";
} }
@ -61,7 +57,7 @@ public class PublisherMember : ModelBase
public Guid PublisherId { get; set; } public Guid PublisherId { get; set; }
[JsonIgnore] public Publisher Publisher { get; set; } = null!; [JsonIgnore] public Publisher Publisher { get; set; } = null!;
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account.Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
public PublisherMemberRole Role { get; set; } = PublisherMemberRole.Viewer; public PublisherMemberRole Role { get; set; } = PublisherMemberRole.Viewer;
public Instant? JoinedAt { get; set; } public Instant? JoinedAt { get; set; }
@ -81,7 +77,7 @@ public class PublisherSubscription : ModelBase
public Guid PublisherId { get; set; } public Guid PublisherId { get; set; }
[JsonIgnore] public Publisher Publisher { get; set; } = null!; [JsonIgnore] public Publisher Publisher { get; set; } = null!;
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
[JsonIgnore] public Account.Account Account { get; set; } = null!; [JsonIgnore] public Shared.Models.Account Account { get; set; } = null!;
public PublisherSubscriptionStatus Status { get; set; } = PublisherSubscriptionStatus.Active; public PublisherSubscriptionStatus Status { get; set; } = PublisherSubscriptionStatus.Active;
public int Tier { get; set; } = 0; public int Tier { get; set; } = 0;

View File

@ -1,12 +1,10 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Sphere.Chat;
using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Realm; namespace DysonNetwork.Shared.Models;
[Index(nameof(Slug), IsUnique = true)] [Index(nameof(Slug), IsUnique = true)]
public class Realm : ModelBase, IIdentifiedResource public class Realm : ModelBase, IIdentifiedResource
@ -25,14 +23,13 @@ public class Realm : ModelBase, IIdentifiedResource
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Picture { get; set; } [Column(TypeName = "jsonb")] public CloudFileReferenceObject? Picture { get; set; }
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Background { get; set; } [Column(TypeName = "jsonb")] public CloudFileReferenceObject? Background { get; set; }
[Column(TypeName = "jsonb")] public Account.VerificationMark? Verification { get; set; } [Column(TypeName = "jsonb")] public VerificationMark? Verification { get; set; }
[JsonIgnore] public ICollection<RealmMember> Members { get; set; } = new List<RealmMember>(); [JsonIgnore] public ICollection<RealmMember> Members { get; set; } = new List<RealmMember>();
[JsonIgnore] public ICollection<ChatRoom> ChatRooms { get; set; } = new List<ChatRoom>(); [JsonIgnore] public ICollection<ChatRoom> ChatRooms { get; set; } = new List<ChatRoom>();
[JsonIgnore] public ICollection<RealmTag> RealmTags { get; set; } = new List<RealmTag>();
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
[JsonIgnore] public Account.Account Account { get; set; } = null!; [JsonIgnore] public Shared.Models.Account Account { get; set; } = null!;
public string ResourceIdentifier => $"realm/{Id}"; public string ResourceIdentifier => $"realm/{Id}";
} }
@ -49,7 +46,7 @@ public class RealmMember : ModelBase
public Guid RealmId { get; set; } public Guid RealmId { get; set; }
public Realm Realm { get; set; } = null!; public Realm Realm { get; set; } = null!;
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account.Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
public int Role { get; set; } = RealmMemberRole.Normal; public int Role { get; set; } = RealmMemberRole.Normal;
public Instant? JoinedAt { get; set; } public Instant? JoinedAt { get; set; }

View File

@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization;
using DysonNetwork.Sphere.Chat.Realtime;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Chat; namespace DysonNetwork.Shared.Models;
public class RealtimeCall : ModelBase public class RealtimeCall : ModelBase
{ {

View File

@ -1,6 +1,6 @@
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Account; namespace DysonNetwork.Shared.Models;
public enum RelationshipStatus : short public enum RelationshipStatus : short
{ {
@ -12,9 +12,9 @@ public enum RelationshipStatus : short
public class Relationship : ModelBase public class Relationship : ModelBase
{ {
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
public Guid RelatedId { get; set; } public Guid RelatedId { get; set; }
public Account Related { get; set; } = null!; public Shared.Models.Account Related { get; set; } = null!;
public Instant? ExpiredAt { get; set; } public Instant? ExpiredAt { get; set; }

View File

@ -1,11 +1,10 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Sphere.Developer;
using NodaTime; using NodaTime;
using Point = NetTopologySuite.Geometries.Point; using Point = NetTopologySuite.Geometries.Point;
namespace DysonNetwork.Sphere.Auth; namespace DysonNetwork.Shared.Models;
public class Session : ModelBase public class Session : ModelBase
{ {
@ -15,7 +14,7 @@ public class Session : ModelBase
public Instant? ExpiredAt { get; set; } public Instant? ExpiredAt { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
[JsonIgnore] public Account.Account Account { get; set; } = null!; [JsonIgnore] public Account Account { get; set; } = null!;
public Guid ChallengeId { get; set; } public Guid ChallengeId { get; set; }
public Challenge Challenge { get; set; } = null!; public Challenge Challenge { get; set; } = null!;
public Guid? AppId { get; set; } public Guid? AppId { get; set; }
@ -49,9 +48,9 @@ public class Challenge : ModelBase
public int FailedAttempts { get; set; } public int FailedAttempts { get; set; }
public ChallengePlatform Platform { get; set; } = ChallengePlatform.Unidentified; public ChallengePlatform Platform { get; set; } = ChallengePlatform.Unidentified;
public ChallengeType Type { get; set; } = ChallengeType.Login; public ChallengeType Type { get; set; } = ChallengeType.Login;
[Column(TypeName = "jsonb")] public List<Guid> BlacklistFactors { get; set; } = new(); [Column(TypeName = "jsonb")] public List<Guid> BlacklistFactors { get; set; } = [];
[Column(TypeName = "jsonb")] public List<string> Audiences { get; set; } = new(); [Column(TypeName = "jsonb")] public List<string> Audiences { get; set; } = [];
[Column(TypeName = "jsonb")] public List<string> Scopes { get; set; } = new(); [Column(TypeName = "jsonb")] public List<string> Scopes { get; set; } = [];
[MaxLength(128)] public string? IpAddress { get; set; } [MaxLength(128)] public string? IpAddress { get; set; }
[MaxLength(512)] public string? UserAgent { get; set; } [MaxLength(512)] public string? UserAgent { get; set; }
[MaxLength(256)] public string? DeviceId { get; set; } [MaxLength(256)] public string? DeviceId { get; set; }
@ -59,7 +58,7 @@ public class Challenge : ModelBase
public Point? Location { get; set; } public Point? Location { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
[JsonIgnore] public Account.Account Account { get; set; } = null!; [JsonIgnore] public Account Account { get; set; } = null!;
public Challenge Normalize() public Challenge Normalize()
{ {

View File

@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
namespace DysonNetwork.Sphere.Wallet; namespace DysonNetwork.Shared.Models;
public record class SubscriptionTypeData( public record class SubscriptionTypeData(
string Identifier, string Identifier,
@ -138,7 +138,7 @@ public class Subscription : ModelBase
public Instant? RenewalAt { get; set; } public Instant? RenewalAt { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account.Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
[NotMapped] [NotMapped]
public bool IsAvailable public bool IsAvailable

View File

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace DysonNetwork.Sphere.Account; namespace DysonNetwork.Shared.Models;
/// <summary> /// <summary>
/// The verification info of a resource /// The verification info of a resource

View File

@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace DysonNetwork.Sphere.Wallet; namespace DysonNetwork.Shared.Models;
public class Wallet : ModelBase public class Wallet : ModelBase
{ {
@ -10,7 +10,7 @@ public class Wallet : ModelBase
public ICollection<WalletPocket> Pockets { get; set; } = new List<WalletPocket>(); public ICollection<WalletPocket> Pockets { get; set; } = new List<WalletPocket>();
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account.Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
} }
public class WalletPocket : ModelBase public class WalletPocket : ModelBase

View File

@ -26,5 +26,5 @@ public class AbuseReport : ModelBase
[MaxLength(8192)] public string? Resolution { get; set; } [MaxLength(8192)] public string? Resolution { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public Account Account { get; set; } = null!; public Shared.Models.Account Account { get; set; } = null!;
} }

View File

@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
using NodaTime.Extensions; using NodaTime.Extensions;
using System.Collections.Generic; using System.Collections.Generic;
using DysonNetwork.Shared.Models;
namespace DysonNetwork.Sphere.Account; namespace DysonNetwork.Sphere.Account;
@ -20,9 +21,9 @@ public class AccountController(
) : ControllerBase ) : ControllerBase
{ {
[HttpGet("{name}")] [HttpGet("{name}")]
[ProducesResponseType<Account>(StatusCodes.Status200OK)] [ProducesResponseType<Shared.Models.Account>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Account?>> GetByName(string name) public async Task<ActionResult<Shared.Models.Account?>> GetByName(string name)
{ {
var account = await db.Accounts var account = await db.Accounts
.Include(e => e.Badges) .Include(e => e.Badges)
@ -73,9 +74,9 @@ public class AccountController(
} }
[HttpPost] [HttpPost]
[ProducesResponseType<Account>(StatusCodes.Status200OK)] [ProducesResponseType<Shared.Models.Account>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Account>> CreateAccount([FromBody] AccountCreateRequest request) public async Task<ActionResult<Shared.Models.Account>> CreateAccount([FromBody] AccountCreateRequest request)
{ {
if (!await auth.ValidateCaptcha(request.CaptchaToken)) return BadRequest("Invalid captcha token."); if (!await auth.ValidateCaptcha(request.CaptchaToken)) return BadRequest("Invalid captcha token.");
@ -163,7 +164,7 @@ public class AccountController(
} }
[HttpGet("search")] [HttpGet("search")]
public async Task<List<Account>> Search([FromQuery] string query, [FromQuery] int take = 20) public async Task<List<Shared.Models.Account>> Search([FromQuery] string query, [FromQuery] int take = 20)
{ {
if (string.IsNullOrWhiteSpace(query)) if (string.IsNullOrWhiteSpace(query))
return []; return [];

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Auth; using DysonNetwork.Sphere.Auth;
using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Permission;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
@ -22,10 +23,10 @@ public class AccountCurrentController(
) : ControllerBase ) : ControllerBase
{ {
[HttpGet] [HttpGet]
[ProducesResponseType<Account>(StatusCodes.Status200OK)] [ProducesResponseType<Shared.Models.Account>(StatusCodes.Status200OK)]
public async Task<ActionResult<Account>> GetCurrentIdentity() public async Task<ActionResult<Shared.Models.Account>> GetCurrentIdentity()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var account = await db.Accounts var account = await db.Accounts
@ -44,9 +45,9 @@ public class AccountCurrentController(
} }
[HttpPatch] [HttpPatch]
public async Task<ActionResult<Account>> UpdateBasicInfo([FromBody] BasicInfoRequest request) public async Task<ActionResult<Shared.Models.Account>> UpdateBasicInfo([FromBody] BasicInfoRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var account = await db.Accounts.FirstAsync(a => a.Id == currentUser.Id); var account = await db.Accounts.FirstAsync(a => a.Id == currentUser.Id);
@ -77,7 +78,7 @@ public class AccountCurrentController(
[HttpPatch("profile")] [HttpPatch("profile")]
public async Task<ActionResult<Profile>> UpdateProfile([FromBody] ProfileRequest request) public async Task<ActionResult<Profile>> UpdateProfile([FromBody] ProfileRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var profile = await db.AccountProfiles var profile = await db.AccountProfiles
@ -162,7 +163,7 @@ public class AccountCurrentController(
[HttpDelete] [HttpDelete]
public async Task<ActionResult> RequestDeleteAccount() public async Task<ActionResult> RequestDeleteAccount()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
try try
{ {
@ -179,7 +180,7 @@ public class AccountCurrentController(
[HttpGet("statuses")] [HttpGet("statuses")]
public async Task<ActionResult<Status>> GetCurrentStatus() public async Task<ActionResult<Status>> GetCurrentStatus()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var status = await events.GetStatus(currentUser.Id); var status = await events.GetStatus(currentUser.Id);
return Ok(status); return Ok(status);
} }
@ -188,7 +189,7 @@ public class AccountCurrentController(
[RequiredPermission("global", "accounts.statuses.update")] [RequiredPermission("global", "accounts.statuses.update")]
public async Task<ActionResult<Status>> UpdateStatus([FromBody] AccountController.StatusRequest request) public async Task<ActionResult<Status>> UpdateStatus([FromBody] AccountController.StatusRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();
var status = await db.AccountStatuses var status = await db.AccountStatuses
@ -215,7 +216,7 @@ public class AccountCurrentController(
[RequiredPermission("global", "accounts.statuses.create")] [RequiredPermission("global", "accounts.statuses.create")]
public async Task<ActionResult<Status>> CreateStatus([FromBody] AccountController.StatusRequest request) public async Task<ActionResult<Status>> CreateStatus([FromBody] AccountController.StatusRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var status = new Status var status = new Status
{ {
@ -233,7 +234,7 @@ public class AccountCurrentController(
[HttpDelete("me/statuses")] [HttpDelete("me/statuses")]
public async Task<ActionResult> DeleteStatus() public async Task<ActionResult> DeleteStatus()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();
var status = await db.AccountStatuses var status = await db.AccountStatuses
@ -250,7 +251,7 @@ public class AccountCurrentController(
[HttpGet("check-in")] [HttpGet("check-in")]
public async Task<ActionResult<CheckInResult>> GetCheckInResult() public async Task<ActionResult<CheckInResult>> GetCheckInResult()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();
@ -270,7 +271,7 @@ public class AccountCurrentController(
[HttpPost("check-in")] [HttpPost("check-in")]
public async Task<ActionResult<CheckInResult>> DoCheckIn([FromBody] string? captchaToken) public async Task<ActionResult<CheckInResult>> DoCheckIn([FromBody] string? captchaToken)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var isAvailable = await events.CheckInDailyIsAvailable(currentUser); var isAvailable = await events.CheckInDailyIsAvailable(currentUser);
if (!isAvailable) if (!isAvailable)
@ -297,7 +298,7 @@ public class AccountCurrentController(
public async Task<ActionResult<List<DailyEventResponse>>> GetEventCalendar([FromQuery] int? month, public async Task<ActionResult<List<DailyEventResponse>>> GetEventCalendar([FromQuery] int? month,
[FromQuery] int? year) [FromQuery] int? year)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var currentDate = SystemClock.Instance.GetCurrentInstant().InUtc().Date; var currentDate = SystemClock.Instance.GetCurrentInstant().InUtc().Date;
month ??= currentDate.Month; month ??= currentDate.Month;
@ -318,7 +319,7 @@ public class AccountCurrentController(
[FromQuery] int offset = 0 [FromQuery] int offset = 0
) )
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var query = db.ActionLogs var query = db.ActionLogs
.Where(log => log.AccountId == currentUser.Id) .Where(log => log.AccountId == currentUser.Id)
@ -338,7 +339,7 @@ public class AccountCurrentController(
[HttpGet("factors")] [HttpGet("factors")]
public async Task<ActionResult<List<AccountAuthFactor>>> GetAuthFactors() public async Task<ActionResult<List<AccountAuthFactor>>> GetAuthFactors()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var factors = await db.AccountAuthFactors var factors = await db.AccountAuthFactors
.Include(f => f.Account) .Include(f => f.Account)
@ -358,7 +359,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<AccountAuthFactor>> CreateAuthFactor([FromBody] AuthFactorRequest request) public async Task<ActionResult<AccountAuthFactor>> CreateAuthFactor([FromBody] AuthFactorRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
if (await accounts.CheckAuthFactorExists(currentUser, request.Type)) if (await accounts.CheckAuthFactorExists(currentUser, request.Type))
return BadRequest($"Auth factor with type {request.Type} is already exists."); return BadRequest($"Auth factor with type {request.Type} is already exists.");
@ -370,7 +371,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<AccountAuthFactor>> EnableAuthFactor(Guid id, [FromBody] string? code) public async Task<ActionResult<AccountAuthFactor>> EnableAuthFactor(Guid id, [FromBody] string? code)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var factor = await db.AccountAuthFactors var factor = await db.AccountAuthFactors
.Where(f => f.AccountId == currentUser.Id && f.Id == id) .Where(f => f.AccountId == currentUser.Id && f.Id == id)
@ -392,7 +393,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<AccountAuthFactor>> DisableAuthFactor(Guid id) public async Task<ActionResult<AccountAuthFactor>> DisableAuthFactor(Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var factor = await db.AccountAuthFactors var factor = await db.AccountAuthFactors
.Where(f => f.AccountId == currentUser.Id && f.Id == id) .Where(f => f.AccountId == currentUser.Id && f.Id == id)
@ -414,7 +415,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<AccountAuthFactor>> DeleteAuthFactor(Guid id) public async Task<ActionResult<AccountAuthFactor>> DeleteAuthFactor(Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var factor = await db.AccountAuthFactors var factor = await db.AccountAuthFactors
.Where(f => f.AccountId == currentUser.Id && f.Id == id) .Where(f => f.AccountId == currentUser.Id && f.Id == id)
@ -445,7 +446,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<List<AuthorizedDevice>>> GetDevices() public async Task<ActionResult<List<AuthorizedDevice>>> GetDevices()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser || if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser ||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized(); HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
Response.Headers.Append("X-Auth-Session", currentSession.Id.ToString()); Response.Headers.Append("X-Auth-Session", currentSession.Id.ToString());
@ -480,7 +481,7 @@ public class AccountCurrentController(
[FromQuery] int offset = 0 [FromQuery] int offset = 0
) )
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser || if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser ||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized(); HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
var query = db.AuthSessions var query = db.AuthSessions
@ -505,7 +506,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<Session>> DeleteSession(Guid id) public async Task<ActionResult<Session>> DeleteSession(Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
try try
{ {
@ -522,7 +523,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<Session>> DeleteCurrentSession() public async Task<ActionResult<Session>> DeleteCurrentSession()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser || if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser ||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized(); HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
try try
@ -539,7 +540,7 @@ public class AccountCurrentController(
[HttpPatch("sessions/{id:guid}/label")] [HttpPatch("sessions/{id:guid}/label")]
public async Task<ActionResult<Session>> UpdateSessionLabel(Guid id, [FromBody] string label) public async Task<ActionResult<Session>> UpdateSessionLabel(Guid id, [FromBody] string label)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
try try
{ {
@ -555,7 +556,7 @@ public class AccountCurrentController(
[HttpPatch("sessions/current/label")] [HttpPatch("sessions/current/label")]
public async Task<ActionResult<Session>> UpdateCurrentSessionLabel([FromBody] string label) public async Task<ActionResult<Session>> UpdateCurrentSessionLabel([FromBody] string label)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser || if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser ||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized(); HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
try try
@ -573,7 +574,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<List<AccountContact>>> GetContacts() public async Task<ActionResult<List<AccountContact>>> GetContacts()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var contacts = await db.AccountContacts var contacts = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id) .Where(c => c.AccountId == currentUser.Id)
@ -592,7 +593,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<AccountContact>> CreateContact([FromBody] AccountContactRequest request) public async Task<ActionResult<AccountContact>> CreateContact([FromBody] AccountContactRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
try try
{ {
@ -609,7 +610,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<AccountContact>> VerifyContact(Guid id) public async Task<ActionResult<AccountContact>> VerifyContact(Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var contact = await db.AccountContacts var contact = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id && c.Id == id) .Where(c => c.AccountId == currentUser.Id && c.Id == id)
@ -631,7 +632,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<AccountContact>> SetPrimaryContact(Guid id) public async Task<ActionResult<AccountContact>> SetPrimaryContact(Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var contact = await db.AccountContacts var contact = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id && c.Id == id) .Where(c => c.AccountId == currentUser.Id && c.Id == id)
@ -653,7 +654,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<AccountContact>> DeleteContact(Guid id) public async Task<ActionResult<AccountContact>> DeleteContact(Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var contact = await db.AccountContacts var contact = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id && c.Id == id) .Where(c => c.AccountId == currentUser.Id && c.Id == id)
@ -676,7 +677,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<List<Badge>>> GetBadges() public async Task<ActionResult<List<Badge>>> GetBadges()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var badges = await db.Badges var badges = await db.Badges
.Where(b => b.AccountId == currentUser.Id) .Where(b => b.AccountId == currentUser.Id)
@ -688,7 +689,7 @@ public class AccountCurrentController(
[Authorize] [Authorize]
public async Task<ActionResult<Badge>> ActivateBadge(Guid id) public async Task<ActionResult<Badge>> ActivateBadge(Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
try try
{ {

View File

@ -1,4 +1,5 @@
using System.Globalization; using System.Globalization;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Activity; using DysonNetwork.Sphere.Activity;
using DysonNetwork.Sphere.Connection; using DysonNetwork.Sphere.Connection;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
@ -139,7 +140,7 @@ public class AccountEventService(
return results; return results;
} }
public async Task<Status> CreateStatus(Account user, Status status) public async Task<Status> CreateStatus(Shared.Models.Account user, Status status)
{ {
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();
await db.AccountStatuses await db.AccountStatuses
@ -152,7 +153,7 @@ public class AccountEventService(
return status; return status;
} }
public async Task ClearStatus(Account user, Status status) public async Task ClearStatus(Shared.Models.Account user, Status status)
{ {
status.ClearedAt = SystemClock.Instance.GetCurrentInstant(); status.ClearedAt = SystemClock.Instance.GetCurrentInstant();
db.Update(status); db.Update(status);
@ -164,7 +165,7 @@ public class AccountEventService(
private const string CaptchaCacheKey = "CheckInCaptcha_"; private const string CaptchaCacheKey = "CheckInCaptcha_";
private const int CaptchaProbabilityPercent = 20; private const int CaptchaProbabilityPercent = 20;
public async Task<bool> CheckInDailyDoAskCaptcha(Account user) public async Task<bool> CheckInDailyDoAskCaptcha(Shared.Models.Account user)
{ {
var cacheKey = $"{CaptchaCacheKey}{user.Id}"; var cacheKey = $"{CaptchaCacheKey}{user.Id}";
var needsCaptcha = await cache.GetAsync<bool?>(cacheKey); var needsCaptcha = await cache.GetAsync<bool?>(cacheKey);
@ -176,7 +177,7 @@ public class AccountEventService(
return result; return result;
} }
public async Task<bool> CheckInDailyIsAvailable(Account user) public async Task<bool> CheckInDailyIsAvailable(Shared.Models.Account user)
{ {
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();
var lastCheckIn = await db.AccountCheckInResults var lastCheckIn = await db.AccountCheckInResults
@ -195,7 +196,7 @@ public class AccountEventService(
public const string CheckInLockKey = "CheckInLock_"; public const string CheckInLockKey = "CheckInLock_";
public async Task<CheckInResult> CheckInDaily(Account user) public async Task<CheckInResult> CheckInDaily(Shared.Models.Account user)
{ {
var lockKey = $"{CheckInLockKey}{user.Id}"; var lockKey = $"{CheckInLockKey}{user.Id}";
@ -280,7 +281,7 @@ public class AccountEventService(
return result; return result;
} }
public async Task<List<DailyEventResponse>> GetEventCalendar(Account user, int month, int year = 0, public async Task<List<DailyEventResponse>> GetEventCalendar(Shared.Models.Account user, int month, int year = 0,
bool replaceInvisible = false) bool replaceInvisible = false)
{ {
if (year == 0) if (year == 0)

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account.Proto; using DysonNetwork.Sphere.Account.Proto;
using Grpc.Core; using Grpc.Core;
using Google.Protobuf.WellKnownTypes; using Google.Protobuf.WellKnownTypes;
@ -50,7 +51,7 @@ public class AccountGrpcService : DysonNetwork.Sphere.Account.Proto.AccountServi
return ToAccountResponse(account); return ToAccountResponse(account);
} }
private async Task<DysonNetwork.Sphere.Account.Account> GetAccountFromContext(ServerCallContext context) private async Task<Shared.Models.Account> GetAccountFromContext(ServerCallContext context)
{ {
var authorizationHeader = context.RequestHeaders.FirstOrDefault(h => h.Key == "authorization"); var authorizationHeader = context.RequestHeaders.FirstOrDefault(h => h.Key == "authorization");
if (authorizationHeader == null) if (authorizationHeader == null)
@ -73,7 +74,7 @@ public class AccountGrpcService : DysonNetwork.Sphere.Account.Proto.AccountServi
return session.Account; return session.Account;
} }
private AccountResponse ToAccountResponse(DysonNetwork.Sphere.Account.Account account) private AccountResponse ToAccountResponse(Shared.Models.Account account)
{ {
var emailContact = account.Contacts.FirstOrDefault(c => c.Type == AccountContactType.Email); var emailContact = account.Contacts.FirstOrDefault(c => c.Type == AccountContactType.Email);
return new AccountResponse return new AccountResponse

View File

@ -1,4 +1,5 @@
using System.Globalization; using System.Globalization;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Auth; using DysonNetwork.Sphere.Auth;
using DysonNetwork.Sphere.Auth.OpenId; using DysonNetwork.Sphere.Auth.OpenId;
using DysonNetwork.Sphere.Email; using DysonNetwork.Sphere.Email;
@ -26,7 +27,7 @@ public class AccountService(
ILogger<AccountService> logger ILogger<AccountService> logger
) )
{ {
public static void SetCultureInfo(Account account) public static void SetCultureInfo(Shared.Models.Account account)
{ {
SetCultureInfo(account.Language); SetCultureInfo(account.Language);
} }
@ -40,12 +41,12 @@ public class AccountService(
public const string AccountCachePrefix = "account:"; public const string AccountCachePrefix = "account:";
public async Task PurgeAccountCache(Account account) public async Task PurgeAccountCache(Shared.Models.Account account)
{ {
await cache.RemoveGroupAsync($"{AccountCachePrefix}{account.Id}"); await cache.RemoveGroupAsync($"{AccountCachePrefix}{account.Id}");
} }
public async Task<Account?> LookupAccount(string probe) public async Task<Shared.Models.Account?> LookupAccount(string probe)
{ {
var account = await db.Accounts.Where(a => a.Name == probe).FirstOrDefaultAsync(); var account = await db.Accounts.Where(a => a.Name == probe).FirstOrDefaultAsync();
if (account is not null) return account; if (account is not null) return account;
@ -57,7 +58,7 @@ public class AccountService(
return contact?.Account; return contact?.Account;
} }
public async Task<Account?> LookupAccountByConnection(string identifier, string provider) public async Task<Shared.Models.Account?> LookupAccountByConnection(string identifier, string provider)
{ {
var connection = await db.AccountConnections var connection = await db.AccountConnections
.Where(c => c.ProvidedIdentifier == identifier && c.Provider == provider) .Where(c => c.ProvidedIdentifier == identifier && c.Provider == provider)
@ -74,7 +75,7 @@ public class AccountService(
return profile?.Level; return profile?.Level;
} }
public async Task<Account> CreateAccount( public async Task<Shared.Models.Account> CreateAccount(
string name, string name,
string nick, string nick,
string email, string email,
@ -91,7 +92,7 @@ public class AccountService(
if (dupeNameCount > 0) if (dupeNameCount > 0)
throw new InvalidOperationException("Account name has already been taken."); throw new InvalidOperationException("Account name has already been taken.");
var account = new Account var account = new Shared.Models.Account
{ {
Name = name, Name = name,
Nick = nick, Nick = nick,
@ -159,7 +160,7 @@ public class AccountService(
} }
} }
public async Task<Account> CreateAccount(OidcUserInfo userInfo) public async Task<Shared.Models.Account> CreateAccount(OidcUserInfo userInfo)
{ {
if (string.IsNullOrEmpty(userInfo.Email)) if (string.IsNullOrEmpty(userInfo.Email))
throw new ArgumentException("Email is required for account creation"); throw new ArgumentException("Email is required for account creation");
@ -182,7 +183,7 @@ public class AccountService(
); );
} }
public async Task RequestAccountDeletion(Account account) public async Task RequestAccountDeletion(Shared.Models.Account account)
{ {
var spell = await spells.CreateMagicSpell( var spell = await spells.CreateMagicSpell(
account, account,
@ -194,7 +195,7 @@ public class AccountService(
await spells.NotifyMagicSpell(spell); await spells.NotifyMagicSpell(spell);
} }
public async Task RequestPasswordReset(Account account) public async Task RequestPasswordReset(Shared.Models.Account account)
{ {
var spell = await spells.CreateMagicSpell( var spell = await spells.CreateMagicSpell(
account, account,
@ -206,7 +207,7 @@ public class AccountService(
await spells.NotifyMagicSpell(spell); await spells.NotifyMagicSpell(spell);
} }
public async Task<bool> CheckAuthFactorExists(Account account, AccountAuthFactorType type) public async Task<bool> CheckAuthFactorExists(Shared.Models.Account account, AccountAuthFactorType type)
{ {
var isExists = await db.AccountAuthFactors var isExists = await db.AccountAuthFactors
.Where(x => x.AccountId == account.Id && x.Type == type) .Where(x => x.AccountId == account.Id && x.Type == type)
@ -214,7 +215,7 @@ public class AccountService(
return isExists; return isExists;
} }
public async Task<AccountAuthFactor?> CreateAuthFactor(Account account, AccountAuthFactorType type, string? secret) public async Task<AccountAuthFactor?> CreateAuthFactor(Shared.Models.Account account, AccountAuthFactorType type, string? secret)
{ {
AccountAuthFactor? factor = null; AccountAuthFactor? factor = null;
switch (type) switch (type)
@ -345,7 +346,7 @@ public class AccountService(
/// <param name="account">The owner of the auth factor</param> /// <param name="account">The owner of the auth factor</param>
/// <param name="factor">The auth factor needed to send code</param> /// <param name="factor">The auth factor needed to send code</param>
/// <param name="hint">The part of the contact method for verification</param> /// <param name="hint">The part of the contact method for verification</param>
public async Task SendFactorCode(Account account, AccountAuthFactor factor, string? hint = null) public async Task SendFactorCode(Shared.Models.Account account, AccountAuthFactor factor, string? hint = null)
{ {
var code = new Random().Next(100000, 999999).ToString("000000"); var code = new Random().Next(100000, 999999).ToString("000000");
@ -454,7 +455,7 @@ public class AccountService(
); );
} }
public async Task<Session> UpdateSessionLabel(Account account, Guid sessionId, string label) public async Task<Session> UpdateSessionLabel(Shared.Models.Account account, Guid sessionId, string label)
{ {
var session = await db.AuthSessions var session = await db.AuthSessions
.Include(s => s.Challenge) .Include(s => s.Challenge)
@ -477,7 +478,7 @@ public class AccountService(
return session; return session;
} }
public async Task DeleteSession(Account account, Guid sessionId) public async Task DeleteSession(Shared.Models.Account account, Guid sessionId)
{ {
var session = await db.AuthSessions var session = await db.AuthSessions
.Include(s => s.Challenge) .Include(s => s.Challenge)
@ -503,7 +504,7 @@ public class AccountService(
await cache.RemoveAsync($"{DysonTokenAuthHandler.AuthCachePrefix}{item.Id}"); await cache.RemoveAsync($"{DysonTokenAuthHandler.AuthCachePrefix}{item.Id}");
} }
public async Task<AccountContact> CreateContactMethod(Account account, AccountContactType type, string content) public async Task<AccountContact> CreateContactMethod(Shared.Models.Account account, AccountContactType type, string content)
{ {
var contact = new AccountContact var contact = new AccountContact
{ {
@ -518,7 +519,7 @@ public class AccountService(
return contact; return contact;
} }
public async Task VerifyContactMethod(Account account, AccountContact contact) public async Task VerifyContactMethod(Shared.Models.Account account, AccountContact contact)
{ {
var spell = await spells.CreateMagicSpell( var spell = await spells.CreateMagicSpell(
account, account,
@ -530,7 +531,7 @@ public class AccountService(
await spells.NotifyMagicSpell(spell); await spells.NotifyMagicSpell(spell);
} }
public async Task<AccountContact> SetContactMethodPrimary(Account account, AccountContact contact) public async Task<AccountContact> SetContactMethodPrimary(Shared.Models.Account account, AccountContact contact)
{ {
if (contact.AccountId != account.Id) if (contact.AccountId != account.Id)
throw new InvalidOperationException("Contact method does not belong to this account."); throw new InvalidOperationException("Contact method does not belong to this account.");
@ -559,7 +560,7 @@ public class AccountService(
} }
} }
public async Task DeleteContactMethod(Account account, AccountContact contact) public async Task DeleteContactMethod(Shared.Models.Account account, AccountContact contact)
{ {
if (contact.AccountId != account.Id) if (contact.AccountId != account.Id)
throw new InvalidOperationException("Contact method does not belong to this account."); throw new InvalidOperationException("Contact method does not belong to this account.");
@ -574,7 +575,7 @@ public class AccountService(
/// This method will grant a badge to the account. /// This method will grant a badge to the account.
/// Shouldn't be exposed to normal user and the user itself. /// Shouldn't be exposed to normal user and the user itself.
/// </summary> /// </summary>
public async Task<Badge> GrantBadge(Account account, Badge badge) public async Task<Badge> GrantBadge(Shared.Models.Account account, Badge badge)
{ {
badge.AccountId = account.Id; badge.AccountId = account.Id;
db.Badges.Add(badge); db.Badges.Add(badge);
@ -586,7 +587,7 @@ public class AccountService(
/// This method will revoke a badge from the account. /// This method will revoke a badge from the account.
/// Shouldn't be exposed to normal user and the user itself. /// Shouldn't be exposed to normal user and the user itself.
/// </summary> /// </summary>
public async Task RevokeBadge(Account account, Guid badgeId) public async Task RevokeBadge(Shared.Models.Account account, Guid badgeId)
{ {
var badge = await db.Badges var badge = await db.Badges
.Where(b => b.AccountId == account.Id && b.Id == badgeId) .Where(b => b.AccountId == account.Id && b.Id == badgeId)
@ -604,7 +605,7 @@ public class AccountService(
await db.SaveChangesAsync(); await db.SaveChangesAsync();
} }
public async Task ActiveBadge(Account account, Guid badgeId) public async Task ActiveBadge(Shared.Models.Account account, Guid badgeId)
{ {
await using var transaction = await db.Database.BeginTransactionAsync(); await using var transaction = await db.Database.BeginTransactionAsync();

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using Quartz; using Quartz;
using DysonNetwork.Sphere.Connection; using DysonNetwork.Sphere.Connection;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
@ -20,7 +21,7 @@ public class ActionLogService(GeoIpService geo, FlushBufferService fbs)
} }
public void CreateActionLogFromRequest(string action, Dictionary<string, object> meta, HttpRequest request, public void CreateActionLogFromRequest(string action, Dictionary<string, object> meta, HttpRequest request,
Account? account = null) Shared.Models.Account? account = null)
{ {
var log = new ActionLog var log = new ActionLog
{ {
@ -31,14 +32,14 @@ public class ActionLogService(GeoIpService geo, FlushBufferService fbs)
Location = geo.GetPointFromIp(request.HttpContext.Connection.RemoteIpAddress?.ToString()) Location = geo.GetPointFromIp(request.HttpContext.Connection.RemoteIpAddress?.ToString())
}; };
if (request.HttpContext.Items["CurrentUser"] is Account currentUser) if (request.HttpContext.Items["CurrentUser"] is Shared.Models.Account currentUser)
log.AccountId = currentUser.Id; log.AccountId = currentUser.Id;
else if (account != null) else if (account != null)
log.AccountId = account.Id; log.AccountId = account.Id;
else else
throw new ArgumentException("No user context was found"); throw new ArgumentException("No user context was found");
if (request.HttpContext.Items["CurrentSession"] is Auth.Session currentSession) if (request.HttpContext.Items["CurrentSession"] is Session currentSession)
log.SessionId = currentSession.Id; log.SessionId = currentSession.Id;
fbs.Enqueue(log); fbs.Enqueue(log);

View File

@ -26,5 +26,5 @@ public class MagicSpell : ModelBase
[Column(TypeName = "jsonb")] public Dictionary<string, object> Meta { get; set; } = new(); [Column(TypeName = "jsonb")] public Dictionary<string, object> Meta { get; set; } = new();
public Guid? AccountId { get; set; } public Guid? AccountId { get; set; }
public Account? Account { get; set; } public Shared.Models.Account? Account { get; set; }
} }

View File

@ -1,6 +1,7 @@
using System.Globalization; using System.Globalization;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text.Json; using System.Text.Json;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Email; using DysonNetwork.Sphere.Email;
using DysonNetwork.Sphere.Pages.Emails; using DysonNetwork.Sphere.Pages.Emails;
using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Permission;
@ -21,7 +22,7 @@ public class MagicSpellService(
) )
{ {
public async Task<MagicSpell> CreateMagicSpell( public async Task<MagicSpell> CreateMagicSpell(
Account account, Shared.Models.Account account,
MagicSpellType type, MagicSpellType type,
Dictionary<string, object> meta, Dictionary<string, object> meta,
Instant? expiredAt = null, Instant? expiredAt = null,

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Auth; using DysonNetwork.Sphere.Auth;
using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Permission;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -17,7 +18,7 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
public async Task<ActionResult<int>> CountUnreadNotifications() public async Task<ActionResult<int>> CountUnreadNotifications()
{ {
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
if (currentUserValue is not Account currentUser) return Unauthorized(); if (currentUserValue is not Shared.Models.Account currentUser) return Unauthorized();
var count = await db.Notifications var count = await db.Notifications
.Where(s => s.AccountId == currentUser.Id && s.ViewedAt == null) .Where(s => s.AccountId == currentUser.Id && s.ViewedAt == null)
@ -35,7 +36,7 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
) )
{ {
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
if (currentUserValue is not Account currentUser) return Unauthorized(); if (currentUserValue is not Shared.Models.Account currentUser) return Unauthorized();
var totalCount = await db.Notifications var totalCount = await db.Notifications
.Where(s => s.AccountId == currentUser.Id) .Where(s => s.AccountId == currentUser.Id)
@ -67,7 +68,7 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
{ {
HttpContext.Items.TryGetValue("CurrentSession", out var currentSessionValue); HttpContext.Items.TryGetValue("CurrentSession", out var currentSessionValue);
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
var currentUser = currentUserValue as Account; var currentUser = currentUserValue as Shared.Models.Account;
if (currentUser == null) return Unauthorized(); if (currentUser == null) return Unauthorized();
var currentSession = currentSessionValue as Session; var currentSession = currentSessionValue as Session;
if (currentSession == null) return Unauthorized(); if (currentSession == null) return Unauthorized();
@ -85,7 +86,7 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
{ {
HttpContext.Items.TryGetValue("CurrentSession", out var currentSessionValue); HttpContext.Items.TryGetValue("CurrentSession", out var currentSessionValue);
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
var currentUser = currentUserValue as Account; var currentUser = currentUserValue as Shared.Models.Account;
if (currentUser == null) return Unauthorized(); if (currentUser == null) return Unauthorized();
var currentSession = currentSessionValue as Session; var currentSession = currentSessionValue as Session;
if (currentSession == null) return Unauthorized(); if (currentSession == null) return Unauthorized();

View File

@ -1,5 +1,6 @@
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Connection; using DysonNetwork.Sphere.Connection;
using EFCore.BulkExtensions; using EFCore.BulkExtensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -24,7 +25,7 @@ public class NotificationService(
} }
public async Task<NotificationPushSubscription> SubscribePushNotification( public async Task<NotificationPushSubscription> SubscribePushNotification(
Account account, Shared.Models.Account account,
NotificationPushProvider provider, NotificationPushProvider provider,
string deviceId, string deviceId,
string deviceToken string deviceToken
@ -70,7 +71,7 @@ public class NotificationService(
} }
public async Task<Notification> SendNotification( public async Task<Notification> SendNotification(
Account account, Shared.Models.Account account,
string topic, string topic,
string? title = null, string? title = null,
string? subtitle = null, string? subtitle = null,
@ -176,7 +177,7 @@ public class NotificationService(
await _PushNotification(notification, subscribers); await _PushNotification(notification, subscribers);
} }
public async Task SendNotificationBatch(Notification notification, List<Account> accounts, bool save = false) public async Task SendNotificationBatch(Notification notification, List<Shared.Models.Account> accounts, bool save = false)
{ {
if (save) if (save)
{ {

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -15,7 +16,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
public async Task<ActionResult<List<Relationship>>> ListRelationships([FromQuery] int offset = 0, public async Task<ActionResult<List<Relationship>>> ListRelationships([FromQuery] int offset = 0,
[FromQuery] int take = 20) [FromQuery] int take = 20)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var query = db.AccountRelationships.AsQueryable() var query = db.AccountRelationships.AsQueryable()
@ -46,7 +47,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[Authorize] [Authorize]
public async Task<ActionResult<List<Relationship>>> ListSentRequests() public async Task<ActionResult<List<Relationship>>> ListSentRequests()
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var relationships = await db.AccountRelationships var relationships = await db.AccountRelationships
.Where(r => r.AccountId == currentUser.Id && r.Status == RelationshipStatus.Pending) .Where(r => r.AccountId == currentUser.Id && r.Status == RelationshipStatus.Pending)
@ -69,7 +70,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
public async Task<ActionResult<Relationship>> CreateRelationship(Guid userId, public async Task<ActionResult<Relationship>> CreateRelationship(Guid userId,
[FromBody] RelationshipRequest request) [FromBody] RelationshipRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var relatedUser = await db.Accounts.FindAsync(userId); var relatedUser = await db.Accounts.FindAsync(userId);
if (relatedUser is null) return NotFound("Account was not found."); if (relatedUser is null) return NotFound("Account was not found.");
@ -92,7 +93,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
public async Task<ActionResult<Relationship>> UpdateRelationship(Guid userId, public async Task<ActionResult<Relationship>> UpdateRelationship(Guid userId,
[FromBody] RelationshipRequest request) [FromBody] RelationshipRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
try try
{ {
@ -113,7 +114,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[Authorize] [Authorize]
public async Task<ActionResult<Relationship>> GetRelationship(Guid userId) public async Task<ActionResult<Relationship>> GetRelationship(Guid userId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var now = Instant.FromDateTimeUtc(DateTime.UtcNow); var now = Instant.FromDateTimeUtc(DateTime.UtcNow);
var queries = db.AccountRelationships.AsQueryable() var queries = db.AccountRelationships.AsQueryable()
@ -133,7 +134,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[Authorize] [Authorize]
public async Task<ActionResult<Relationship>> SendFriendRequest(Guid userId) public async Task<ActionResult<Relationship>> SendFriendRequest(Guid userId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var relatedUser = await db.Accounts.FindAsync(userId); var relatedUser = await db.Accounts.FindAsync(userId);
if (relatedUser is null) return NotFound("Account was not found."); if (relatedUser is null) return NotFound("Account was not found.");
@ -158,7 +159,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[Authorize] [Authorize]
public async Task<ActionResult> DeleteFriendRequest(Guid userId) public async Task<ActionResult> DeleteFriendRequest(Guid userId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
try try
{ {
@ -175,7 +176,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[Authorize] [Authorize]
public async Task<ActionResult<Relationship>> AcceptFriendRequest(Guid userId) public async Task<ActionResult<Relationship>> AcceptFriendRequest(Guid userId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var relationship = await rels.GetRelationship(userId, currentUser.Id, RelationshipStatus.Pending); var relationship = await rels.GetRelationship(userId, currentUser.Id, RelationshipStatus.Pending);
if (relationship is null) return NotFound("Friend request was not found."); if (relationship is null) return NotFound("Friend request was not found.");
@ -195,7 +196,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[Authorize] [Authorize]
public async Task<ActionResult<Relationship>> DeclineFriendRequest(Guid userId) public async Task<ActionResult<Relationship>> DeclineFriendRequest(Guid userId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var relationship = await rels.GetRelationship(userId, currentUser.Id, RelationshipStatus.Pending); var relationship = await rels.GetRelationship(userId, currentUser.Id, RelationshipStatus.Pending);
if (relationship is null) return NotFound("Friend request was not found."); if (relationship is null) return NotFound("Friend request was not found.");
@ -215,7 +216,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[Authorize] [Authorize]
public async Task<ActionResult<Relationship>> BlockUser(Guid userId) public async Task<ActionResult<Relationship>> BlockUser(Guid userId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var relatedUser = await db.Accounts.FindAsync(userId); var relatedUser = await db.Accounts.FindAsync(userId);
if (relatedUser is null) return NotFound("Account was not found."); if (relatedUser is null) return NotFound("Account was not found.");
@ -235,7 +236,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[Authorize] [Authorize]
public async Task<ActionResult<Relationship>> UnblockUser(Guid userId) public async Task<ActionResult<Relationship>> UnblockUser(Guid userId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var relatedUser = await db.Accounts.FindAsync(userId); var relatedUser = await db.Accounts.FindAsync(userId);
if (relatedUser is null) return NotFound("Account was not found."); if (relatedUser is null) return NotFound("Account was not found.");

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
@ -34,7 +35,7 @@ public class RelationshipService(AppDatabase db, ICacheService cache)
return relationship; return relationship;
} }
public async Task<Relationship> CreateRelationship(Account sender, Account target, RelationshipStatus status) public async Task<Relationship> CreateRelationship(Shared.Models.Account sender, Shared.Models.Account target, RelationshipStatus status)
{ {
if (status == RelationshipStatus.Pending) if (status == RelationshipStatus.Pending)
throw new InvalidOperationException( throw new InvalidOperationException(
@ -57,14 +58,14 @@ public class RelationshipService(AppDatabase db, ICacheService cache)
return relationship; return relationship;
} }
public async Task<Relationship> BlockAccount(Account sender, Account target) public async Task<Relationship> BlockAccount(Shared.Models.Account sender, Shared.Models.Account target)
{ {
if (await HasExistingRelationship(sender.Id, target.Id)) if (await HasExistingRelationship(sender.Id, target.Id))
return await UpdateRelationship(sender.Id, target.Id, RelationshipStatus.Blocked); return await UpdateRelationship(sender.Id, target.Id, RelationshipStatus.Blocked);
return await CreateRelationship(sender, target, RelationshipStatus.Blocked); return await CreateRelationship(sender, target, RelationshipStatus.Blocked);
} }
public async Task<Relationship> UnblockAccount(Account sender, Account target) public async Task<Relationship> UnblockAccount(Shared.Models.Account sender, Shared.Models.Account target)
{ {
var relationship = await GetRelationship(sender.Id, target.Id, RelationshipStatus.Blocked); var relationship = await GetRelationship(sender.Id, target.Id, RelationshipStatus.Blocked);
if (relationship is null) throw new ArgumentException("There is no relationship between you and the user."); if (relationship is null) throw new ArgumentException("There is no relationship between you and the user.");
@ -76,7 +77,7 @@ public class RelationshipService(AppDatabase db, ICacheService cache)
return relationship; return relationship;
} }
public async Task<Relationship> SendFriendRequest(Account sender, Account target) public async Task<Relationship> SendFriendRequest(Shared.Models.Account sender, Shared.Models.Account target)
{ {
if (await HasExistingRelationship(sender.Id, target.Id)) if (await HasExistingRelationship(sender.Id, target.Id))
throw new InvalidOperationException("Found existing relationship between you and target user."); throw new InvalidOperationException("Found existing relationship between you and target user.");
@ -152,7 +153,7 @@ public class RelationshipService(AppDatabase db, ICacheService cache)
return relationship; return relationship;
} }
public async Task<List<Guid>> ListAccountFriends(Account account) public async Task<List<Guid>> ListAccountFriends(Shared.Models.Account account)
{ {
var cacheKey = $"{UserFriendsCacheKeyPrefix}{account.Id}"; var cacheKey = $"{UserFriendsCacheKeyPrefix}{account.Id}";
var friends = await cache.GetAsync<List<Guid>>(cacheKey); var friends = await cache.GetAsync<List<Guid>>(cacheKey);
@ -171,7 +172,7 @@ public class RelationshipService(AppDatabase db, ICacheService cache)
return friends ?? []; return friends ?? [];
} }
public async Task<List<Guid>> ListAccountBlocked(Account account) public async Task<List<Guid>> ListAccountBlocked(Shared.Models.Account account)
{ {
var cacheKey = $"{UserBlockedCacheKeyPrefix}{account.Id}"; var cacheKey = $"{UserBlockedCacheKeyPrefix}{account.Id}";
var blocked = await cache.GetAsync<List<Guid>>(cacheKey); var blocked = await cache.GetAsync<List<Guid>>(cacheKey);

View File

@ -45,7 +45,7 @@ public class ActivityController(
var debugIncludeSet = debugInclude?.Split(',').ToHashSet() ?? new HashSet<string>(); var debugIncludeSet = debugInclude?.Split(',').ToHashSet() ?? new HashSet<string>();
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
return currentUserValue is not Account.Account currentUser return currentUserValue is not Shared.Models.Account currentUser
? Ok(await acts.GetActivitiesForAnyone(take, cursorTimestamp, debugIncludeSet)) ? Ok(await acts.GetActivitiesForAnyone(take, cursorTimestamp, debugIncludeSet))
: Ok(await acts.GetActivities(take, cursorTimestamp, currentUser, filter, debugIncludeSet)); : Ok(await acts.GetActivities(take, cursorTimestamp, currentUser, filter, debugIncludeSet));
} }

View File

@ -32,7 +32,7 @@ public class ActivityService(
if (cursor == null && (debugInclude.Contains("realms") || Random.Shared.NextDouble() < 0.2)) if (cursor == null && (debugInclude.Contains("realms") || Random.Shared.NextDouble() < 0.2))
{ {
var realms = await ds.GetPublicRealmsAsync(null, null, 5, 0, true); var realms = await ds.GetPublicRealmsAsync(null, 5, 0, true);
if (realms.Count > 0) if (realms.Count > 0)
{ {
activities.Add(new DiscoveryActivity( activities.Add(new DiscoveryActivity(
@ -118,7 +118,7 @@ public class ActivityService(
public async Task<List<Activity>> GetActivities( public async Task<List<Activity>> GetActivities(
int take, int take,
Instant? cursor, Instant? cursor,
Account.Account currentUser, Shared.Models.Account currentUser,
string? filter = null, string? filter = null,
HashSet<string>? debugInclude = null HashSet<string>? debugInclude = null
) )
@ -132,7 +132,7 @@ public class ActivityService(
{ {
if (cursor == null && (debugInclude.Contains("realms") || Random.Shared.NextDouble() < 0.2)) if (cursor == null && (debugInclude.Contains("realms") || Random.Shared.NextDouble() < 0.2))
{ {
var realms = await ds.GetPublicRealmsAsync(null, null, 5, 0, true); var realms = await ds.GetPublicRealmsAsync(null, 5, 0, true);
if (realms.Count > 0) if (realms.Count > 0)
{ {
activities.Add(new DiscoveryActivity( activities.Add(new DiscoveryActivity(
@ -257,7 +257,7 @@ public class ActivityService(
return score + postCount; return score + postCount;
} }
private async Task<List<Publisher.Publisher>> GetPopularPublishers(int take) private async Task<List<Shared.Models.Publisher>> GetPopularPublishers(int take)
{ {
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();
var recent = now.Minus(Duration.FromDays(7)); var recent = now.Minus(Duration.FromDays(7));

View File

@ -1,5 +1,6 @@
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Auth; using DysonNetwork.Sphere.Auth;
using DysonNetwork.Sphere.Chat; using DysonNetwork.Sphere.Chat;
@ -20,11 +21,6 @@ using Quartz;
namespace DysonNetwork.Sphere; namespace DysonNetwork.Sphere;
public interface IIdentifiedResource
{
public string ResourceIdentifier { get; }
}
public abstract class ModelBase public abstract class ModelBase
{ {
public Instant CreatedAt { get; set; } public Instant CreatedAt { get; set; }
@ -42,7 +38,7 @@ public class AppDatabase(
public DbSet<PermissionGroupMember> PermissionGroupMembers { get; set; } public DbSet<PermissionGroupMember> PermissionGroupMembers { get; set; }
public DbSet<MagicSpell> MagicSpells { get; set; } public DbSet<MagicSpell> MagicSpells { get; set; }
public DbSet<Account.Account> Accounts { get; set; } public DbSet<Shared.Models.Account> Accounts { get; set; }
public DbSet<AccountConnection> AccountConnections { get; set; } public DbSet<AccountConnection> AccountConnections { get; set; }
public DbSet<Profile> AccountProfiles { get; set; } public DbSet<Profile> AccountProfiles { get; set; }
public DbSet<AccountContact> AccountContacts { get; set; } public DbSet<AccountContact> AccountContacts { get; set; }
@ -62,7 +58,7 @@ public class AppDatabase(
public DbSet<CloudFile> Files { get; set; } public DbSet<CloudFile> Files { get; set; }
public DbSet<CloudFileReference> FileReferences { get; set; } public DbSet<CloudFileReference> FileReferences { get; set; }
public DbSet<Publisher.Publisher> Publishers { get; set; } public DbSet<Shared.Models.Publisher> Publishers { get; set; }
public DbSet<PublisherMember> PublisherMembers { get; set; } public DbSet<PublisherMember> PublisherMembers { get; set; }
public DbSet<PublisherSubscription> PublisherSubscriptions { get; set; } public DbSet<PublisherSubscription> PublisherSubscriptions { get; set; }
public DbSet<PublisherFeature> PublisherFeatures { get; set; } public DbSet<PublisherFeature> PublisherFeatures { get; set; }
@ -73,10 +69,8 @@ public class AppDatabase(
public DbSet<PostCategory> PostCategories { get; set; } public DbSet<PostCategory> PostCategories { get; set; }
public DbSet<PostCollection> PostCollections { get; set; } public DbSet<PostCollection> PostCollections { get; set; }
public DbSet<Realm.Realm> Realms { get; set; } public DbSet<Shared.Models.Realm> Realms { get; set; }
public DbSet<RealmMember> RealmMembers { get; set; } public DbSet<RealmMember> RealmMembers { get; set; }
public DbSet<Tag> Tags { get; set; }
public DbSet<RealmTag> RealmTags { get; set; }
public DbSet<ChatRoom> ChatRooms { get; set; } public DbSet<ChatRoom> ChatRooms { get; set; }
public DbSet<ChatMember> ChatMembers { get; set; } public DbSet<ChatMember> ChatMembers { get; set; }
@ -87,7 +81,7 @@ public class AppDatabase(
public DbSet<Sticker.Sticker> Stickers { get; set; } public DbSet<Sticker.Sticker> Stickers { get; set; }
public DbSet<StickerPack> StickerPacks { get; set; } public DbSet<StickerPack> StickerPacks { get; set; }
public DbSet<Wallet.Wallet> Wallets { get; set; } public DbSet<Shared.Models.Wallet> Wallets { get; set; }
public DbSet<WalletPocket> WalletPockets { get; set; } public DbSet<WalletPocket> WalletPockets { get; set; }
public DbSet<Order> PaymentOrders { get; set; } public DbSet<Order> PaymentOrders { get; set; }
public DbSet<Transaction> PaymentTransactions { get; set; } public DbSet<Transaction> PaymentTransactions { get; set; }
@ -243,19 +237,6 @@ public class AppDatabase(
.HasForeignKey(pm => pm.AccountId) .HasForeignKey(pm => pm.AccountId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<RealmTag>()
.HasKey(rt => new { rt.RealmId, rt.TagId });
modelBuilder.Entity<RealmTag>()
.HasOne(rt => rt.Realm)
.WithMany(r => r.RealmTags)
.HasForeignKey(rt => rt.RealmId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<RealmTag>()
.HasOne(rt => rt.Tag)
.WithMany(t => t.RealmTags)
.HasForeignKey(rt => rt.TagId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<ChatMember>() modelBuilder.Entity<ChatMember>()
.HasKey(pm => new { pm.Id }); .HasKey(pm => new { pm.Id });
modelBuilder.Entity<ChatMember>() modelBuilder.Entity<ChatMember>()

View File

@ -12,6 +12,7 @@ using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using NodaTime; using NodaTime;
using System.Text; using System.Text;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Auth.OidcProvider.Controllers; using DysonNetwork.Sphere.Auth.OidcProvider.Controllers;
using DysonNetwork.Sphere.Auth.OidcProvider.Services; using DysonNetwork.Sphere.Auth.OidcProvider.Services;
using SystemClock = NodaTime.SystemClock; using SystemClock = NodaTime.SystemClock;

View File

@ -6,6 +6,7 @@ using NodaTime;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Text.Json; using System.Text.Json;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Connection; using DysonNetwork.Sphere.Connection;
namespace DysonNetwork.Sphere.Auth; namespace DysonNetwork.Sphere.Auth;

View File

@ -5,6 +5,9 @@ using DysonNetwork.Sphere.Account;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
using System.Text.Json; using System.Text.Json;
using DysonNetwork.Shared.Models;
using Challenge = DysonNetwork.Sphere.Auth.Proto.Challenge;
using Session = DysonNetwork.Sphere.Auth.Proto.Session;
namespace DysonNetwork.Sphere.Auth; namespace DysonNetwork.Sphere.Auth;

View File

@ -1,5 +1,6 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text.Json; using System.Text.Json;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -24,7 +25,7 @@ public class AuthService(
/// <param name="request">The request context</param> /// <param name="request">The request context</param>
/// <param name="account">The account to login</param> /// <param name="account">The account to login</param>
/// <returns>The required steps to login</returns> /// <returns>The required steps to login</returns>
public async Task<int> DetectChallengeRisk(HttpRequest request, Account.Account account) public async Task<int> DetectChallengeRisk(HttpRequest request, Shared.Models.Account account)
{ {
// 1) Find out how many authentication factors the account has enabled. // 1) Find out how many authentication factors the account has enabled.
var maxSteps = await db.AccountAuthFactors var maxSteps = await db.AccountAuthFactors
@ -73,7 +74,7 @@ public class AuthService(
return totalRequiredSteps; return totalRequiredSteps;
} }
public async Task<Session> CreateSessionForOidcAsync(Account.Account account, Instant time, Guid? customAppId = null) public async Task<Session> CreateSessionForOidcAsync(Shared.Models.Account account, Instant time, Guid? customAppId = null)
{ {
var challenge = new Challenge var challenge = new Challenge
{ {

View File

@ -1,4 +1,5 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using DysonNetwork.Shared.Models;
namespace DysonNetwork.Sphere.Auth; namespace DysonNetwork.Sphere.Auth;

View File

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@ -114,7 +115,7 @@ public class OidcProviderController(
[Authorize] [Authorize]
public async Task<IActionResult> GetUserInfo() public async Task<IActionResult> GetUserInfo()
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser || if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser ||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized(); HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
// Get requested scopes from the token // Get requested scopes from the token

View File

@ -2,6 +2,7 @@ using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Auth.OidcProvider.Models; using DysonNetwork.Sphere.Auth.OidcProvider.Models;
using DysonNetwork.Sphere.Auth.OidcProvider.Options; using DysonNetwork.Sphere.Auth.OidcProvider.Options;
using DysonNetwork.Sphere.Auth.OidcProvider.Responses; using DysonNetwork.Sphere.Auth.OidcProvider.Responses;

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -25,7 +26,7 @@ public class ConnectionController(
[HttpGet] [HttpGet]
public async Task<ActionResult<List<AccountConnection>>> GetConnections() public async Task<ActionResult<List<AccountConnection>>> GetConnections()
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
return Unauthorized(); return Unauthorized();
var connections = await db.AccountConnections var connections = await db.AccountConnections
@ -48,7 +49,7 @@ public class ConnectionController(
[HttpDelete("{id:guid}")] [HttpDelete("{id:guid}")]
public async Task<ActionResult> RemoveConnection(Guid id) public async Task<ActionResult> RemoveConnection(Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
return Unauthorized(); return Unauthorized();
var connection = await db.AccountConnections var connection = await db.AccountConnections
@ -66,7 +67,7 @@ public class ConnectionController(
[HttpPost("/auth/connect/apple/mobile")] [HttpPost("/auth/connect/apple/mobile")]
public async Task<ActionResult> ConnectAppleMobile([FromBody] AppleMobileConnectRequest request) public async Task<ActionResult> ConnectAppleMobile([FromBody] AppleMobileConnectRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
return Unauthorized(); return Unauthorized();
if (GetOidcService("apple") is not AppleOidcService appleService) if (GetOidcService("apple") is not AppleOidcService appleService)
@ -132,7 +133,7 @@ public class ConnectionController(
[HttpPost("connect")] [HttpPost("connect")]
public async Task<ActionResult<object>> InitiateConnection([FromBody] ConnectProviderRequest request) public async Task<ActionResult<object>> InitiateConnection([FromBody] ConnectProviderRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
return Unauthorized(); return Unauthorized();
var oidcService = GetOidcService(request.Provider); var oidcService = GetOidcService(request.Provider);

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -32,7 +33,7 @@ public class OidcController(
var oidcService = GetOidcService(provider); var oidcService = GetOidcService(provider);
// If the user is already authenticated, treat as an account connection request // If the user is already authenticated, treat as an account connection request
if (HttpContext.Items["CurrentUser"] is Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is Shared.Models.Account currentUser)
{ {
var state = Guid.NewGuid().ToString(); var state = Guid.NewGuid().ToString();
var nonce = Guid.NewGuid().ToString(); var nonce = Guid.NewGuid().ToString();
@ -125,7 +126,7 @@ public class OidcController(
}; };
} }
private async Task<Account.Account> FindOrCreateAccount(OidcUserInfo userInfo, string provider) private async Task<Shared.Models.Account> FindOrCreateAccount(OidcUserInfo userInfo, string provider)
{ {
if (string.IsNullOrEmpty(userInfo.Email)) if (string.IsNullOrEmpty(userInfo.Email))
throw new ArgumentException("Email is required for account creation"); throw new ArgumentException("Email is required for account creation");

View File

@ -1,6 +1,7 @@
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -190,7 +191,7 @@ public abstract class OidcService(
/// </summary> /// </summary>
public async Task<Challenge> CreateChallengeForUserAsync( public async Task<Challenge> CreateChallengeForUserAsync(
OidcUserInfo userInfo, OidcUserInfo userInfo,
Account.Account account, Shared.Models.Account account,
HttpContext request, HttpContext request,
string deviceId string deviceId
) )

View File

@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Permission;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -32,7 +33,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
[Authorize] [Authorize]
public async Task<ActionResult<Dictionary<Guid, ChatSummaryResponse>>> GetChatSummary() public async Task<ActionResult<Dictionary<Guid, ChatSummaryResponse>>> GetChatSummary()
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var unreadMessages = await cs.CountUnreadMessageForUser(currentUser.Id); var unreadMessages = await cs.CountUnreadMessageForUser(currentUser.Id);
var lastMessages = await cs.ListLastMessageForUser(currentUser.Id); var lastMessages = await cs.ListLastMessageForUser(currentUser.Id);
@ -65,7 +66,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
public async Task<ActionResult<List<Message>>> ListMessages(Guid roomId, [FromQuery] int offset, public async Task<ActionResult<List<Message>>> ListMessages(Guid roomId, [FromQuery] int offset,
[FromQuery] int take = 20) [FromQuery] int take = 20)
{ {
var currentUser = HttpContext.Items["CurrentUser"] as Account.Account; var currentUser = HttpContext.Items["CurrentUser"] as Shared.Models.Account;
var room = await db.ChatRooms.FirstOrDefaultAsync(r => r.Id == roomId); var room = await db.ChatRooms.FirstOrDefaultAsync(r => r.Id == roomId);
if (room is null) return NotFound(); if (room is null) return NotFound();
@ -102,7 +103,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
[HttpGet("{roomId:guid}/messages/{messageId:guid}")] [HttpGet("{roomId:guid}/messages/{messageId:guid}")]
public async Task<ActionResult<Message>> GetMessage(Guid roomId, Guid messageId) public async Task<ActionResult<Message>> GetMessage(Guid roomId, Guid messageId)
{ {
var currentUser = HttpContext.Items["CurrentUser"] as Account.Account; var currentUser = HttpContext.Items["CurrentUser"] as Shared.Models.Account;
var room = await db.ChatRooms.FirstOrDefaultAsync(r => r.Id == roomId); var room = await db.ChatRooms.FirstOrDefaultAsync(r => r.Id == roomId);
if (room is null) return NotFound(); if (room is null) return NotFound();
@ -139,7 +140,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
[RequiredPermission("global", "chat.messages.create")] [RequiredPermission("global", "chat.messages.create")]
public async Task<ActionResult> SendMessage([FromBody] SendMessageRequest request, Guid roomId) public async Task<ActionResult> SendMessage([FromBody] SendMessageRequest request, Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
request.Content = TextSanitizer.Sanitize(request.Content); request.Content = TextSanitizer.Sanitize(request.Content);
if (string.IsNullOrWhiteSpace(request.Content) && if (string.IsNullOrWhiteSpace(request.Content) &&
@ -216,7 +217,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
[Authorize] [Authorize]
public async Task<ActionResult> UpdateMessage([FromBody] SendMessageRequest request, Guid roomId, Guid messageId) public async Task<ActionResult> UpdateMessage([FromBody] SendMessageRequest request, Guid roomId, Guid messageId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
request.Content = TextSanitizer.Sanitize(request.Content); request.Content = TextSanitizer.Sanitize(request.Content);
@ -269,7 +270,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
[Authorize] [Authorize]
public async Task<ActionResult> DeleteMessage(Guid roomId, Guid messageId) public async Task<ActionResult> DeleteMessage(Guid roomId, Guid messageId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var message = await db.ChatMessages var message = await db.ChatMessages
.Include(m => m.Sender) .Include(m => m.Sender)
@ -295,7 +296,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
[HttpPost("{roomId:guid}/sync")] [HttpPost("{roomId:guid}/sync")]
public async Task<ActionResult<SyncResponse>> GetSyncData([FromBody] SyncRequest request, Guid roomId) public async Task<ActionResult<SyncResponse>> GetSyncData([FromBody] SyncRequest request, Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
return Unauthorized(); return Unauthorized();
var isMember = await db.ChatMembers var isMember = await db.ChatMembers

View File

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Localization; using DysonNetwork.Sphere.Localization;
using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Permission;
@ -36,7 +37,7 @@ public class ChatRoomController(
if (chatRoom is null) return NotFound(); if (chatRoom is null) return NotFound();
if (chatRoom.Type != ChatRoomType.DirectMessage) return Ok(chatRoom); if (chatRoom.Type != ChatRoomType.DirectMessage) return Ok(chatRoom);
if (HttpContext.Items["CurrentUser"] is Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is Shared.Models.Account currentUser)
chatRoom = await crs.LoadDirectMessageMembers(chatRoom, currentUser.Id); chatRoom = await crs.LoadDirectMessageMembers(chatRoom, currentUser.Id);
return Ok(chatRoom); return Ok(chatRoom);
@ -46,7 +47,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult<List<ChatRoom>>> ListJoinedChatRooms() public async Task<ActionResult<List<ChatRoom>>> ListJoinedChatRooms()
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
return Unauthorized(); return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
@ -72,7 +73,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult<ChatRoom>> CreateDirectMessage([FromBody] DirectMessageRequest request) public async Task<ActionResult<ChatRoom>> CreateDirectMessage([FromBody] DirectMessageRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
return Unauthorized(); return Unauthorized();
var relatedUser = await db.Accounts.FindAsync(request.RelatedUserId); var relatedUser = await db.Accounts.FindAsync(request.RelatedUserId);
@ -134,7 +135,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult<ChatRoom>> GetDirectChatRoom(Guid userId) public async Task<ActionResult<ChatRoom>> GetDirectChatRoom(Guid userId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
return Unauthorized(); return Unauthorized();
var room = await db.ChatRooms var room = await db.ChatRooms
@ -164,7 +165,7 @@ public class ChatRoomController(
[RequiredPermission("global", "chat.create")] [RequiredPermission("global", "chat.create")]
public async Task<ActionResult<ChatRoom>> CreateChatRoom(ChatRoomRequest request) public async Task<ActionResult<ChatRoom>> CreateChatRoom(ChatRoomRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
if (request.Name is null) return BadRequest("You cannot create a chat room without a name."); if (request.Name is null) return BadRequest("You cannot create a chat room without a name.");
var chatRoom = new ChatRoom var chatRoom = new ChatRoom
@ -236,7 +237,7 @@ public class ChatRoomController(
[HttpPatch("{id:guid}")] [HttpPatch("{id:guid}")]
public async Task<ActionResult<ChatRoom>> UpdateChatRoom(Guid id, [FromBody] ChatRoomRequest request) public async Task<ActionResult<ChatRoom>> UpdateChatRoom(Guid id, [FromBody] ChatRoomRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var chatRoom = await db.ChatRooms var chatRoom = await db.ChatRooms
.Where(e => e.Id == id) .Where(e => e.Id == id)
@ -321,7 +322,7 @@ public class ChatRoomController(
[HttpDelete("{id:guid}")] [HttpDelete("{id:guid}")]
public async Task<ActionResult> DeleteChatRoom(Guid id) public async Task<ActionResult> DeleteChatRoom(Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var chatRoom = await db.ChatRooms var chatRoom = await db.ChatRooms
.Where(e => e.Id == id) .Where(e => e.Id == id)
@ -356,7 +357,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult<ChatMember>> GetRoomIdentity(Guid roomId) public async Task<ActionResult<ChatMember>> GetRoomIdentity(Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
return Unauthorized(); return Unauthorized();
var member = await db.ChatMembers var member = await db.ChatMembers
@ -375,7 +376,7 @@ public class ChatRoomController(
public async Task<ActionResult<List<ChatMember>>> ListMembers(Guid roomId, [FromQuery] int take = 20, public async Task<ActionResult<List<ChatMember>>> ListMembers(Guid roomId, [FromQuery] int take = 20,
[FromQuery] int skip = 0, [FromQuery] bool withStatus = false, [FromQuery] string? status = null) [FromQuery] int skip = 0, [FromQuery] bool withStatus = false, [FromQuery] string? status = null)
{ {
var currentUser = HttpContext.Items["CurrentUser"] as Account.Account; var currentUser = HttpContext.Items["CurrentUser"] as Shared.Models.Account;
var room = await db.ChatRooms var room = await db.ChatRooms
.FirstOrDefaultAsync(r => r.Id == roomId); .FirstOrDefaultAsync(r => r.Id == roomId);
@ -448,7 +449,7 @@ public class ChatRoomController(
public async Task<ActionResult<ChatMember>> InviteMember(Guid roomId, public async Task<ActionResult<ChatMember>> InviteMember(Guid roomId,
[FromBody] ChatMemberRequest request) [FromBody] ChatMemberRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var relatedUser = await db.Accounts.FindAsync(request.RelatedUserId); var relatedUser = await db.Accounts.FindAsync(request.RelatedUserId);
@ -519,7 +520,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult<List<ChatMember>>> ListChatInvites() public async Task<ActionResult<List<ChatMember>>> ListChatInvites()
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var members = await db.ChatMembers var members = await db.ChatMembers
@ -544,7 +545,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult<ChatRoom>> AcceptChatInvite(Guid roomId) public async Task<ActionResult<ChatRoom>> AcceptChatInvite(Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var member = await db.ChatMembers var member = await db.ChatMembers
@ -571,7 +572,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult> DeclineChatInvite(Guid roomId) public async Task<ActionResult> DeclineChatInvite(Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var member = await db.ChatMembers var member = await db.ChatMembers
@ -600,7 +601,7 @@ public class ChatRoomController(
[FromBody] ChatMemberNotifyRequest request [FromBody] ChatMemberNotifyRequest request
) )
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var chatRoom = await db.ChatRooms var chatRoom = await db.ChatRooms
.Where(r => r.Id == roomId) .Where(r => r.Id == roomId)
@ -629,7 +630,7 @@ public class ChatRoomController(
public async Task<ActionResult<ChatMember>> UpdateChatMemberRole(Guid roomId, Guid memberId, [FromBody] int newRole) public async Task<ActionResult<ChatMember>> UpdateChatMemberRole(Guid roomId, Guid memberId, [FromBody] int newRole)
{ {
if (newRole >= ChatMemberRole.Owner) return BadRequest("Unable to set chat member to owner or greater role."); if (newRole >= ChatMemberRole.Owner) return BadRequest("Unable to set chat member to owner or greater role.");
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var chatRoom = await db.ChatRooms var chatRoom = await db.ChatRooms
.Where(r => r.Id == roomId) .Where(r => r.Id == roomId)
@ -688,7 +689,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult> RemoveChatMember(Guid roomId, Guid memberId) public async Task<ActionResult> RemoveChatMember(Guid roomId, Guid memberId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var chatRoom = await db.ChatRooms var chatRoom = await db.ChatRooms
.Where(r => r.Id == roomId) .Where(r => r.Id == roomId)
@ -736,7 +737,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult<ChatRoom>> JoinChatRoom(Guid roomId) public async Task<ActionResult<ChatRoom>> JoinChatRoom(Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var chatRoom = await db.ChatRooms var chatRoom = await db.ChatRooms
.Where(r => r.Id == roomId) .Where(r => r.Id == roomId)
@ -774,7 +775,7 @@ public class ChatRoomController(
[Authorize] [Authorize]
public async Task<ActionResult> LeaveChat(Guid roomId) public async Task<ActionResult> LeaveChat(Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var member = await db.ChatMembers var member = await db.ChatMembers
.Where(m => m.AccountId == currentUser.Id) .Where(m => m.AccountId == currentUser.Id)
@ -807,7 +808,7 @@ public class ChatRoomController(
return NoContent(); return NoContent();
} }
private async Task _SendInviteNotify(ChatMember member, Account.Account sender) private async Task _SendInviteNotify(ChatMember member, Shared.Models.Account sender)
{ {
string title = localizer["ChatInviteTitle"]; string title = localizer["ChatInviteTitle"];

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;

View File

@ -1,4 +1,5 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Chat.Realtime; using DysonNetwork.Sphere.Chat.Realtime;
using DysonNetwork.Sphere.Connection; using DysonNetwork.Sphere.Connection;
@ -241,7 +242,7 @@ public partial class ChatService(
Priority = 10, Priority = 10,
}; };
List<Account.Account> accountsToNotify = []; List<Shared.Models.Account> accountsToNotify = [];
foreach (var member in members) foreach (var member in members)
{ {
scopedWs.SendPacketToAccount(member.AccountId, new WebSocketPacket scopedWs.SendPacketToAccount(member.AccountId, new WebSocketPacket

View File

@ -36,7 +36,7 @@ public interface IRealtimeService
/// <param name="sessionId">The session identifier</param> /// <param name="sessionId">The session identifier</param>
/// <param name="isAdmin">The user is the admin of session</param> /// <param name="isAdmin">The user is the admin of session</param>
/// <returns>User-specific token for the session</returns> /// <returns>User-specific token for the session</returns>
string GetUserToken(Account.Account account, string sessionId, bool isAdmin = false); string GetUserToken(Shared.Models.Account account, string sessionId, bool isAdmin = false);
/// <summary> /// <summary>
/// Processes incoming webhook requests from the realtime service provider /// Processes incoming webhook requests from the realtime service provider

View File

@ -4,6 +4,7 @@ using Livekit.Server.Sdk.Dotnet;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
using System.Text.Json; using System.Text.Json;
using DysonNetwork.Shared.Models;
namespace DysonNetwork.Sphere.Chat.Realtime; namespace DysonNetwork.Sphere.Chat.Realtime;
@ -111,7 +112,7 @@ public class LivekitRealtimeService : IRealtimeService
} }
/// <inheritdoc /> /// <inheritdoc />
public string GetUserToken(Account.Account account, string sessionId, bool isAdmin = false) public string GetUserToken(Shared.Models.Account account, string sessionId, bool isAdmin = false)
{ {
var token = _accessToken.WithIdentity(account.Name) var token = _accessToken.WithIdentity(account.Name)
.WithName(account.Nick) .WithName(account.Nick)

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Chat.Realtime; using DysonNetwork.Sphere.Chat.Realtime;
using Livekit.Server.Sdk.Dotnet; using Livekit.Server.Sdk.Dotnet;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -46,7 +47,7 @@ public class RealtimeCallController(
[Authorize] [Authorize]
public async Task<ActionResult<RealtimeCall>> GetOngoingCall(Guid roomId) public async Task<ActionResult<RealtimeCall>> GetOngoingCall(Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var member = await db.ChatMembers var member = await db.ChatMembers
.Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId) .Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId)
@ -71,7 +72,7 @@ public class RealtimeCallController(
[Authorize] [Authorize]
public async Task<ActionResult<JoinCallResponse>> JoinCall(Guid roomId) public async Task<ActionResult<JoinCallResponse>> JoinCall(Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
// Check if the user is a member of the chat room // Check if the user is a member of the chat room
var member = await db.ChatMembers var member = await db.ChatMembers
@ -144,7 +145,7 @@ public class RealtimeCallController(
[Authorize] [Authorize]
public async Task<ActionResult<RealtimeCall>> StartCall(Guid roomId) public async Task<ActionResult<RealtimeCall>> StartCall(Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var member = await db.ChatMembers var member = await db.ChatMembers
.Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId) .Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId)
@ -163,7 +164,7 @@ public class RealtimeCallController(
[Authorize] [Authorize]
public async Task<ActionResult<RealtimeCall>> EndCall(Guid roomId) public async Task<ActionResult<RealtimeCall>> EndCall(Guid roomId)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var member = await db.ChatMembers var member = await db.ChatMembers
.Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId) .Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId)

View File

@ -1,4 +1,5 @@
using System.Net.WebSockets; using System.Net.WebSockets;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Chat; using DysonNetwork.Sphere.Chat;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -19,7 +20,7 @@ public class MessageReadHandler(
public const string ChatMemberCacheKey = "ChatMember_{0}_{1}"; public const string ChatMemberCacheKey = "ChatMember_{0}_{1}";
public async Task HandleAsync( public async Task HandleAsync(
Account.Account currentUser, Shared.Models.Account currentUser,
string deviceId, string deviceId,
WebSocketPacket packet, WebSocketPacket packet,
WebSocket socket, WebSocket socket,

View File

@ -10,7 +10,7 @@ public class MessageTypingHandler(ChatRoomService crs) : IWebSocketPacketHandler
public string PacketType => "messages.typing"; public string PacketType => "messages.typing";
public async Task HandleAsync( public async Task HandleAsync(
Account.Account currentUser, Shared.Models.Account currentUser,
string deviceId, string deviceId,
WebSocketPacket packet, WebSocketPacket packet,
WebSocket socket, WebSocket socket,

View File

@ -9,7 +9,7 @@ public class MessagesSubscribeHandler(ChatRoomService crs) : IWebSocketPacketHan
public string PacketType => "messages.subscribe"; public string PacketType => "messages.subscribe";
public async Task HandleAsync( public async Task HandleAsync(
Account.Account currentUser, Shared.Models.Account currentUser,
string deviceId, string deviceId,
WebSocketPacket packet, WebSocketPacket packet,
WebSocket socket, WebSocket socket,

View File

@ -8,7 +8,7 @@ public class MessagesUnsubscribeHandler() : IWebSocketPacketHandler
public string PacketType => "messages.unsubscribe"; public string PacketType => "messages.unsubscribe";
public Task HandleAsync( public Task HandleAsync(
Account.Account currentUser, Shared.Models.Account currentUser,
string deviceId, string deviceId,
WebSocketPacket packet, WebSocketPacket packet,
WebSocket socket, WebSocket socket,

View File

@ -5,5 +5,5 @@ namespace DysonNetwork.Sphere.Connection;
public interface IWebSocketPacketHandler public interface IWebSocketPacketHandler
{ {
string PacketType { get; } string PacketType { get; }
Task HandleAsync(Account.Account currentUser, string deviceId, WebSocketPacket packet, WebSocket socket, WebSocketService srv); Task HandleAsync(Shared.Models.Account currentUser, string deviceId, WebSocketPacket packet, WebSocket socket, WebSocketService srv);
} }

View File

@ -40,7 +40,7 @@ public class WebFeed : ModelBase
[Column(TypeName = "jsonb")] public WebFeedConfig Config { get; set; } = new(); [Column(TypeName = "jsonb")] public WebFeedConfig Config { get; set; } = new();
public Guid PublisherId { get; set; } public Guid PublisherId { get; set; }
public Publisher.Publisher Publisher { get; set; } = null!; public Shared.Models.Publisher Publisher { get; set; } = null!;
[JsonIgnore] public ICollection<WebArticle> Articles { get; set; } = new List<WebArticle>(); [JsonIgnore] public ICollection<WebArticle> Articles { get; set; } = new List<WebArticle>();
} }

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Publisher; using DysonNetwork.Sphere.Publisher;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -43,7 +44,7 @@ public class WebFeedController(WebFeedService webFeed, PublisherService ps) : Co
[Authorize] [Authorize]
public async Task<IActionResult> CreateWebFeed([FromRoute] string pubName, [FromBody] WebFeedRequest request) public async Task<IActionResult> CreateWebFeed([FromRoute] string pubName, [FromBody] WebFeedRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
if (string.IsNullOrWhiteSpace(request.Url) || string.IsNullOrWhiteSpace(request.Title)) if (string.IsNullOrWhiteSpace(request.Url) || string.IsNullOrWhiteSpace(request.Title))
return BadRequest("Url and title are required"); return BadRequest("Url and title are required");
@ -62,7 +63,7 @@ public class WebFeedController(WebFeedService webFeed, PublisherService ps) : Co
[Authorize] [Authorize]
public async Task<IActionResult> UpdateFeed([FromRoute] string pubName, Guid id, [FromBody] WebFeedRequest request) public async Task<IActionResult> UpdateFeed([FromRoute] string pubName, Guid id, [FromBody] WebFeedRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var publisher = await ps.GetPublisherByName(pubName); var publisher = await ps.GetPublisherByName(pubName);
if (publisher is null) return NotFound(); if (publisher is null) return NotFound();
@ -82,7 +83,7 @@ public class WebFeedController(WebFeedService webFeed, PublisherService ps) : Co
[Authorize] [Authorize]
public async Task<IActionResult> DeleteFeed([FromRoute] string pubName, Guid id) public async Task<IActionResult> DeleteFeed([FromRoute] string pubName, Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var publisher = await ps.GetPublisherByName(pubName); var publisher = await ps.GetPublisherByName(pubName);
if (publisher is null) return NotFound(); if (publisher is null) return NotFound();
@ -104,7 +105,7 @@ public class WebFeedController(WebFeedService webFeed, PublisherService ps) : Co
[Authorize] [Authorize]
public async Task<ActionResult> Scrap([FromRoute] string pubName, Guid id) public async Task<ActionResult> Scrap([FromRoute] string pubName, Guid id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var publisher = await ps.GetPublisherByName(pubName); var publisher = await ps.GetPublisherByName(pubName);
if (publisher is null) return NotFound(); if (publisher is null) return NotFound();

View File

@ -11,7 +11,7 @@ public class WebFeedService(
WebReaderService webReaderService WebReaderService webReaderService
) )
{ {
public async Task<WebFeed> CreateWebFeedAsync(Publisher.Publisher publisher, public async Task<WebFeed> CreateWebFeedAsync(Shared.Models.Publisher publisher,
WebFeedController.WebFeedRequest request) WebFeedController.WebFeedRequest request)
{ {
var feed = new WebFeed var feed = new WebFeed

View File

@ -1,5 +1,6 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Net.WebSockets; using System.Net.WebSockets;
using DysonNetwork.Shared.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal;
@ -18,8 +19,8 @@ public class WebSocketController(WebSocketService ws, ILogger<WebSocketContext>
{ {
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
HttpContext.Items.TryGetValue("CurrentSession", out var currentSessionValue); HttpContext.Items.TryGetValue("CurrentSession", out var currentSessionValue);
if (currentUserValue is not Account.Account currentUser || if (currentUserValue is not Shared.Models.Account currentUser ||
currentSessionValue is not Auth.Session currentSession) currentSessionValue is not Session currentSession)
{ {
HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
return; return;
@ -69,7 +70,7 @@ public class WebSocketController(WebSocketService ws, ILogger<WebSocketContext>
private async Task _ConnectionEventLoop( private async Task _ConnectionEventLoop(
string deviceId, string deviceId,
Account.Account currentUser, Shared.Models.Account currentUser,
WebSocket webSocket, WebSocket webSocket,
CancellationToken cancellationToken CancellationToken cancellationToken
) )

View File

@ -106,7 +106,7 @@ public class WebSocketService
} }
} }
public async Task HandlePacket(Account.Account currentUser, string deviceId, WebSocketPacket packet, public async Task HandlePacket(Shared.Models.Account currentUser, string deviceId, WebSocketPacket packet,
WebSocket socket) WebSocket socket)
{ {
if (_handlerMap.TryGetValue(packet.Type, out var handler)) if (_handlerMap.TryGetValue(packet.Type, out var handler))

View File

@ -1,139 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Data.Migrations
{
/// <inheritdoc />
public partial class AddOidcProviderSupport : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "remarks",
table: "custom_app_secrets",
newName: "description");
migrationBuilder.AddColumn<bool>(
name: "allow_offline_access",
table: "custom_apps",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "allowed_grant_types",
table: "custom_apps",
type: "character varying(256)",
maxLength: 256,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "allowed_scopes",
table: "custom_apps",
type: "character varying(256)",
maxLength: 256,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "client_uri",
table: "custom_apps",
type: "character varying(1024)",
maxLength: 1024,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "logo_uri",
table: "custom_apps",
type: "character varying(4096)",
maxLength: 4096,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "post_logout_redirect_uris",
table: "custom_apps",
type: "character varying(4096)",
maxLength: 4096,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "redirect_uris",
table: "custom_apps",
type: "character varying(4096)",
maxLength: 4096,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<bool>(
name: "require_pkce",
table: "custom_apps",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "is_oidc",
table: "custom_app_secrets",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.CreateIndex(
name: "ix_custom_app_secrets_secret",
table: "custom_app_secrets",
column: "secret",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "ix_custom_app_secrets_secret",
table: "custom_app_secrets");
migrationBuilder.DropColumn(
name: "allow_offline_access",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "allowed_grant_types",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "allowed_scopes",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "client_uri",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "logo_uri",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "post_logout_redirect_uris",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "redirect_uris",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "require_pkce",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "is_oidc",
table: "custom_app_secrets");
migrationBuilder.RenameColumn(
name: "description",
table: "custom_app_secrets",
newName: "remarks");
}
}
}

View File

@ -1,49 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Data.Migrations
{
/// <inheritdoc />
public partial class AuthSessionWithApp : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "app_id",
table: "auth_sessions",
type: "uuid",
nullable: true);
migrationBuilder.CreateIndex(
name: "ix_auth_sessions_app_id",
table: "auth_sessions",
column: "app_id");
migrationBuilder.AddForeignKey(
name: "fk_auth_sessions_custom_apps_app_id",
table: "auth_sessions",
column: "app_id",
principalTable: "custom_apps",
principalColumn: "id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "fk_auth_sessions_custom_apps_app_id",
table: "auth_sessions");
migrationBuilder.DropIndex(
name: "ix_auth_sessions_app_id",
table: "auth_sessions");
migrationBuilder.DropColumn(
name: "app_id",
table: "auth_sessions");
}
}
}

View File

@ -1,182 +0,0 @@
using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Developer;
using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore.Migrations;
using NodaTime;
#nullable disable
namespace DysonNetwork.Sphere.Data.Migrations
{
/// <inheritdoc />
public partial class CustomAppsRefine : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "allow_offline_access",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "allowed_grant_types",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "allowed_scopes",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "client_uri",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "logo_uri",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "post_logout_redirect_uris",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "redirect_uris",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "require_pkce",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "verified_at",
table: "custom_apps");
migrationBuilder.RenameColumn(
name: "verified_as",
table: "custom_apps",
newName: "description");
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "background",
table: "custom_apps",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<CustomAppLinks>(
name: "links",
table: "custom_apps",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<CustomAppOauthConfig>(
name: "oauth_config",
table: "custom_apps",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "picture",
table: "custom_apps",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<VerificationMark>(
name: "verification",
table: "custom_apps",
type: "jsonb",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "background",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "links",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "oauth_config",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "picture",
table: "custom_apps");
migrationBuilder.DropColumn(
name: "verification",
table: "custom_apps");
migrationBuilder.RenameColumn(
name: "description",
table: "custom_apps",
newName: "verified_as");
migrationBuilder.AddColumn<bool>(
name: "allow_offline_access",
table: "custom_apps",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "allowed_grant_types",
table: "custom_apps",
type: "character varying(256)",
maxLength: 256,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "allowed_scopes",
table: "custom_apps",
type: "character varying(256)",
maxLength: 256,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "client_uri",
table: "custom_apps",
type: "character varying(1024)",
maxLength: 1024,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "logo_uri",
table: "custom_apps",
type: "character varying(4096)",
maxLength: 4096,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "post_logout_redirect_uris",
table: "custom_apps",
type: "character varying(4096)",
maxLength: 4096,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "redirect_uris",
table: "custom_apps",
type: "character varying(4096)",
maxLength: 4096,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<bool>(
name: "require_pkce",
table: "custom_apps",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<Instant>(
name: "verified_at",
table: "custom_apps",
type: "timestamp with time zone",
nullable: true);
}
}
}

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Publisher; using DysonNetwork.Sphere.Publisher;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -47,7 +48,7 @@ public class CustomAppController(CustomAppService customApps, PublisherService p
[Authorize] [Authorize]
public async Task<IActionResult> CreateApp([FromRoute] string pubName, [FromBody] CustomAppRequest request) public async Task<IActionResult> CreateApp([FromRoute] string pubName, [FromBody] CustomAppRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
if (string.IsNullOrWhiteSpace(request.Name) || string.IsNullOrWhiteSpace(request.Slug)) if (string.IsNullOrWhiteSpace(request.Name) || string.IsNullOrWhiteSpace(request.Slug))
return BadRequest("Name and slug are required"); return BadRequest("Name and slug are required");
@ -79,7 +80,7 @@ public class CustomAppController(CustomAppService customApps, PublisherService p
[FromBody] CustomAppRequest request [FromBody] CustomAppRequest request
) )
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var publisher = await ps.GetPublisherByName(pubName); var publisher = await ps.GetPublisherByName(pubName);
if (publisher is null) return NotFound(); if (publisher is null) return NotFound();
@ -109,7 +110,7 @@ public class CustomAppController(CustomAppService customApps, PublisherService p
[FromRoute] Guid id [FromRoute] Guid id
) )
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var publisher = await ps.GetPublisherByName(pubName); var publisher = await ps.GetPublisherByName(pubName);
if (publisher is null) return NotFound(); if (publisher is null) return NotFound();

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Publisher; using DysonNetwork.Sphere.Publisher;
using DysonNetwork.Sphere.Storage; using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -7,7 +8,7 @@ namespace DysonNetwork.Sphere.Developer;
public class CustomAppService(AppDatabase db, FileReferenceService fileRefService) public class CustomAppService(AppDatabase db, FileReferenceService fileRefService)
{ {
public async Task<CustomApp?> CreateAppAsync( public async Task<CustomApp?> CreateAppAsync(
Publisher.Publisher pub, Shared.Models.Publisher pub,
CustomAppController.CustomAppRequest request CustomAppController.CustomAppRequest request
) )
{ {

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Permission;
using DysonNetwork.Sphere.Publisher; using DysonNetwork.Sphere.Publisher;
@ -18,7 +19,7 @@ public class DeveloperController(
: ControllerBase : ControllerBase
{ {
[HttpGet("{name}")] [HttpGet("{name}")]
public async Task<ActionResult<Publisher.Publisher>> GetDeveloper(string name) public async Task<ActionResult<Shared.Models.Publisher>> GetDeveloper(string name)
{ {
var publisher = await db.Publishers var publisher = await db.Publishers
.Where(e => e.Name == name) .Where(e => e.Name == name)
@ -61,9 +62,9 @@ public class DeveloperController(
[HttpGet] [HttpGet]
[Authorize] [Authorize]
public async Task<ActionResult<List<Publisher.Publisher>>> ListJoinedDevelopers() public async Task<ActionResult<List<Shared.Models.Publisher>>> ListJoinedDevelopers()
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var members = await db.PublisherMembers var members = await db.PublisherMembers
@ -91,9 +92,9 @@ public class DeveloperController(
[HttpPost("{name}/enroll")] [HttpPost("{name}/enroll")]
[Authorize] [Authorize]
[RequiredPermission("global", "developers.create")] [RequiredPermission("global", "developers.create")]
public async Task<ActionResult<Publisher.Publisher>> EnrollDeveloperProgram(string name) public async Task<ActionResult<Shared.Models.Publisher>> EnrollDeveloperProgram(string name)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id; var userId = currentUser.Id;
var publisher = await db.Publishers var publisher = await db.Publishers

View File

@ -7,13 +7,12 @@ namespace DysonNetwork.Sphere.Discovery;
public class DiscoveryController(DiscoveryService discoveryService) : ControllerBase public class DiscoveryController(DiscoveryService discoveryService) : ControllerBase
{ {
[HttpGet("realms")] [HttpGet("realms")]
public Task<List<Realm.Realm>> GetPublicRealms( public Task<List<Shared.Models.Realm>> GetPublicRealms(
[FromQuery] string? query, [FromQuery] string? query,
[FromQuery] List<string>? tags,
[FromQuery] int take = 10, [FromQuery] int take = 10,
[FromQuery] int offset = 0 [FromQuery] int offset = 0
) )
{ {
return discoveryService.GetPublicRealmsAsync(query, tags, take, offset); return discoveryService.GetPublicRealmsAsync(query, take, offset);
} }
} }

View File

@ -1,10 +1,10 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace DysonNetwork.Sphere.Discovery; namespace DysonNetwork.Sphere.Discovery;
public class DiscoveryService(AppDatabase appDatabase) public class DiscoveryService(AppDatabase appDatabase)
{ {
public Task<List<Realm.Realm>> GetPublicRealmsAsync(string? query, public Task<List<Shared.Models.Realm>> GetPublicRealmsAsync(string? query,
List<string>? tags,
int take = 10, int take = 10,
int offset = 0, int offset = 0,
bool randomizer = false bool randomizer = false
@ -20,12 +20,9 @@ public class DiscoveryService(AppDatabase appDatabase)
realmsQuery = realmsQuery.Where(r => r.Name.Contains(query) || r.Description.Contains(query)); realmsQuery = realmsQuery.Where(r => r.Name.Contains(query) || r.Description.Contains(query));
} }
if (tags is { Count: > 0 }) realmsQuery = randomizer
realmsQuery = realmsQuery.Where(r => r.RealmTags.Any(rt => tags.Contains(rt.Tag.Name))); ? realmsQuery.OrderBy(r => EF.Functions.Random())
if (randomizer) : realmsQuery.OrderByDescending(r => r.CreatedAt);
realmsQuery = realmsQuery.OrderBy(r => EF.Functions.Random());
else
realmsQuery = realmsQuery.OrderByDescending(r => r.CreatedAt);
return realmsQuery.Skip(offset).Take(take).ToListAsync(); return realmsQuery.Skip(offset).Take(take).ToListAsync();
} }

View File

@ -28,12 +28,12 @@
<PackageReference Include="MailKit" Version="4.11.0" /> <PackageReference Include="MailKit" Version="4.11.0" />
<PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" /> <PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.2" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.3"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.4" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.6" />
<PackageReference Include="MimeTypes" Version="2.5.2"> <PackageReference Include="MimeTypes" Version="2.5.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@ -68,10 +68,10 @@
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" /> <PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.9" /> <PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.9" />
<PackageReference Include="SkiaSharp.NativeAssets.macOS" Version="2.88.9" /> <PackageReference Include="SkiaSharp.NativeAssets.macOS" Version="2.88.9" />
<PackageReference Include="StackExchange.Redis" Version="2.8.37" /> <PackageReference Include="StackExchange.Redis" Version="2.8.41" />
<PackageReference Include="StackExchange.Redis.Extensions.AspNetCore" Version="11.0.0" /> <PackageReference Include="StackExchange.Redis.Extensions.AspNetCore" Version="11.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.0" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.1" />
<PackageReference Include="System.ServiceModel.Syndication" Version="9.0.6" /> <PackageReference Include="System.ServiceModel.Syndication" Version="9.0.6" />
<PackageReference Include="tusdotnet" Version="2.8.1" /> <PackageReference Include="tusdotnet" Version="2.8.1" />
</ItemGroup> </ItemGroup>
@ -83,7 +83,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Migrations\" />
<Folder Include="Discovery\" /> <Folder Include="Discovery\" />
</ItemGroup> </ItemGroup>
@ -173,4 +172,8 @@
<Protobuf Include="Protos\account.proto" GrpcServices="Server" /> <Protobuf Include="Protos\account.proto" GrpcServices="Server" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DysonNetwork.Shared\DysonNetwork.Shared.csproj" />
</ItemGroup>
</Project> </Project>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
using NodaTime;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class EnrichAccountProfile : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Instant>(
name: "birthday",
table: "account_profiles",
type: "timestamp with time zone",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "gender",
table: "account_profiles",
type: "character varying(1024)",
maxLength: 1024,
nullable: true);
migrationBuilder.AddColumn<Instant>(
name: "last_seen_at",
table: "account_profiles",
type: "timestamp with time zone",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "pronouns",
table: "account_profiles",
type: "character varying(1024)",
maxLength: 1024,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "birthday",
table: "account_profiles");
migrationBuilder.DropColumn(
name: "gender",
table: "account_profiles");
migrationBuilder.DropColumn(
name: "last_seen_at",
table: "account_profiles");
migrationBuilder.DropColumn(
name: "pronouns",
table: "account_profiles");
}
}
}

View File

@ -1,52 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class FixProfileRelationship : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "fk_account_profiles_accounts_id",
table: "account_profiles");
migrationBuilder.CreateIndex(
name: "ix_account_profiles_account_id",
table: "account_profiles",
column: "account_id",
unique: true);
migrationBuilder.AddForeignKey(
name: "fk_account_profiles_accounts_account_id",
table: "account_profiles",
column: "account_id",
principalTable: "accounts",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "fk_account_profiles_accounts_account_id",
table: "account_profiles");
migrationBuilder.DropIndex(
name: "ix_account_profiles_account_id",
table: "account_profiles");
migrationBuilder.AddForeignKey(
name: "fk_account_profiles_accounts_id",
table: "account_profiles",
column: "id",
principalTable: "accounts",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,89 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using NodaTime;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class RefactorChatLastRead : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "chat_read_receipts");
migrationBuilder.AlterColumn<string>(
name: "type",
table: "chat_messages",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AddColumn<Instant>(
name: "last_read_at",
table: "chat_members",
type: "timestamp with time zone",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "last_read_at",
table: "chat_members");
migrationBuilder.AlterColumn<string>(
name: "type",
table: "chat_messages",
type: "text",
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.CreateTable(
name: "chat_read_receipts",
columns: table => new
{
message_id = table.Column<Guid>(type: "uuid", nullable: false),
sender_id = table.Column<Guid>(type: "uuid", nullable: false),
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_chat_read_receipts", x => new { x.message_id, x.sender_id });
table.ForeignKey(
name: "fk_chat_read_receipts_chat_members_sender_id",
column: x => x.sender_id,
principalTable: "chat_members",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_chat_read_receipts_chat_messages_message_id",
column: x => x.message_id,
principalTable: "chat_messages",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "ix_chat_read_receipts_message_id_sender_id",
table: "chat_read_receipts",
columns: new[] { "message_id", "sender_id" },
unique: true);
migrationBuilder.CreateIndex(
name: "ix_chat_read_receipts_sender_id",
table: "chat_read_receipts",
column: "sender_id");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class UpdateRealtimeChat : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "ix_notification_push_subscriptions_device_id",
table: "notification_push_subscriptions");
migrationBuilder.DropIndex(
name: "ix_notification_push_subscriptions_device_token",
table: "notification_push_subscriptions");
migrationBuilder.RenameColumn(
name: "title",
table: "chat_realtime_call",
newName: "session_id");
migrationBuilder.AddColumn<string>(
name: "provider_name",
table: "chat_realtime_call",
type: "text",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "upstream",
table: "chat_realtime_call",
type: "jsonb",
nullable: true);
migrationBuilder.CreateIndex(
name: "ix_notification_push_subscriptions_device_token_device_id",
table: "notification_push_subscriptions",
columns: new[] { "device_token", "device_id" },
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "ix_notification_push_subscriptions_device_token_device_id",
table: "notification_push_subscriptions");
migrationBuilder.DropColumn(
name: "provider_name",
table: "chat_realtime_call");
migrationBuilder.DropColumn(
name: "upstream",
table: "chat_realtime_call");
migrationBuilder.RenameColumn(
name: "session_id",
table: "chat_realtime_call",
newName: "title");
migrationBuilder.CreateIndex(
name: "ix_notification_push_subscriptions_device_id",
table: "notification_push_subscriptions",
column: "device_id",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_notification_push_subscriptions_device_token",
table: "notification_push_subscriptions",
column: "device_token",
unique: true);
}
}
}

View File

@ -1,34 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class ModifyRelationshipStatusType : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<short>(
name: "status",
table: "account_relationships",
type: "smallint",
nullable: false,
oldClrType: typeof(int),
oldType: "integer");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "status",
table: "account_relationships",
type: "integer",
nullable: false,
oldClrType: typeof(short),
oldType: "smallint");
}
}
}

View File

@ -1,22 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class LimitedSizeForPictureIdOnPub : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class AddCloudFileUsage : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "usage",
table: "files",
type: "character varying(1024)",
maxLength: 1024,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "usage",
table: "files");
}
}
}

View File

@ -1,436 +0,0 @@
using System;
using System.Collections.Generic;
using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore.Migrations;
using NodaTime;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class RefactorCloudFileReference : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "fk_account_profiles_files_background_id",
table: "account_profiles");
migrationBuilder.DropForeignKey(
name: "fk_account_profiles_files_picture_id",
table: "account_profiles");
migrationBuilder.DropForeignKey(
name: "fk_chat_rooms_files_background_id",
table: "chat_rooms");
migrationBuilder.DropForeignKey(
name: "fk_chat_rooms_files_picture_id",
table: "chat_rooms");
migrationBuilder.DropForeignKey(
name: "fk_posts_posts_threaded_post_id",
table: "posts");
migrationBuilder.DropForeignKey(
name: "fk_publishers_files_background_id",
table: "publishers");
migrationBuilder.DropForeignKey(
name: "fk_publishers_files_picture_id",
table: "publishers");
migrationBuilder.DropForeignKey(
name: "fk_realms_files_background_id",
table: "realms");
migrationBuilder.DropForeignKey(
name: "fk_realms_files_picture_id",
table: "realms");
migrationBuilder.DropForeignKey(
name: "fk_stickers_files_image_id",
table: "stickers");
migrationBuilder.DropIndex(
name: "ix_stickers_image_id",
table: "stickers");
migrationBuilder.DropIndex(
name: "ix_realms_background_id",
table: "realms");
migrationBuilder.DropIndex(
name: "ix_realms_picture_id",
table: "realms");
migrationBuilder.DropIndex(
name: "ix_publishers_background_id",
table: "publishers");
migrationBuilder.DropIndex(
name: "ix_publishers_picture_id",
table: "publishers");
migrationBuilder.DropIndex(
name: "ix_posts_threaded_post_id",
table: "posts");
migrationBuilder.DropIndex(
name: "ix_chat_rooms_background_id",
table: "chat_rooms");
migrationBuilder.DropIndex(
name: "ix_chat_rooms_picture_id",
table: "chat_rooms");
migrationBuilder.DropIndex(
name: "ix_account_profiles_background_id",
table: "account_profiles");
migrationBuilder.DropIndex(
name: "ix_account_profiles_picture_id",
table: "account_profiles");
migrationBuilder.DropColumn(
name: "threaded_post_id",
table: "posts");
migrationBuilder.DropColumn(
name: "expired_at",
table: "files");
migrationBuilder.DropColumn(
name: "usage",
table: "files");
migrationBuilder.DropColumn(
name: "used_count",
table: "files");
migrationBuilder.AlterColumn<string>(
name: "image_id",
table: "stickers",
type: "character varying(32)",
maxLength: 32,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(32)",
oldMaxLength: 32);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "image",
table: "stickers",
type: "jsonb",
nullable: true,
defaultValueSql: "'[]'::jsonb"
);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "background",
table: "realms",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "picture",
table: "realms",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "background",
table: "publishers",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "picture",
table: "publishers",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<List<CloudFileReferenceObject>>(
name: "attachments",
table: "posts",
type: "jsonb",
nullable: false,
defaultValueSql: "'[]'::jsonb"
);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "background",
table: "chat_rooms",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "picture",
table: "chat_rooms",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<List<CloudFileReferenceObject>>(
name: "attachments",
table: "chat_messages",
type: "jsonb",
nullable: false,
defaultValueSql: "'[]'::jsonb"
);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "background",
table: "account_profiles",
type: "jsonb",
nullable: true);
migrationBuilder.AddColumn<CloudFileReferenceObject>(
name: "picture",
table: "account_profiles",
type: "jsonb",
nullable: true);
migrationBuilder.CreateTable(
name: "file_references",
columns: table => new
{
id = table.Column<Guid>(type: "uuid", nullable: false),
file_id = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
usage = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
resource_id = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_file_references", x => x.id);
table.ForeignKey(
name: "fk_file_references_files_file_id",
column: x => x.file_id,
principalTable: "files",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "ix_file_references_file_id",
table: "file_references",
column: "file_id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "file_references");
migrationBuilder.DropColumn(
name: "image",
table: "stickers");
migrationBuilder.DropColumn(
name: "background",
table: "realms");
migrationBuilder.DropColumn(
name: "picture",
table: "realms");
migrationBuilder.DropColumn(
name: "background",
table: "publishers");
migrationBuilder.DropColumn(
name: "picture",
table: "publishers");
migrationBuilder.DropColumn(
name: "attachments",
table: "posts");
migrationBuilder.DropColumn(
name: "background",
table: "chat_rooms");
migrationBuilder.DropColumn(
name: "picture",
table: "chat_rooms");
migrationBuilder.DropColumn(
name: "attachments",
table: "chat_messages");
migrationBuilder.DropColumn(
name: "background",
table: "account_profiles");
migrationBuilder.DropColumn(
name: "picture",
table: "account_profiles");
migrationBuilder.AlterColumn<string>(
name: "image_id",
table: "stickers",
type: "character varying(32)",
maxLength: 32,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(32)",
oldMaxLength: 32,
oldNullable: true);
migrationBuilder.AddColumn<Guid>(
name: "threaded_post_id",
table: "posts",
type: "uuid",
nullable: true);
migrationBuilder.AddColumn<Instant>(
name: "expired_at",
table: "files",
type: "timestamp with time zone",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "usage",
table: "files",
type: "character varying(1024)",
maxLength: 1024,
nullable: true);
migrationBuilder.AddColumn<int>(
name: "used_count",
table: "files",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.CreateIndex(
name: "ix_stickers_image_id",
table: "stickers",
column: "image_id");
migrationBuilder.CreateIndex(
name: "ix_realms_background_id",
table: "realms",
column: "background_id");
migrationBuilder.CreateIndex(
name: "ix_realms_picture_id",
table: "realms",
column: "picture_id");
migrationBuilder.CreateIndex(
name: "ix_publishers_background_id",
table: "publishers",
column: "background_id");
migrationBuilder.CreateIndex(
name: "ix_publishers_picture_id",
table: "publishers",
column: "picture_id");
migrationBuilder.CreateIndex(
name: "ix_posts_threaded_post_id",
table: "posts",
column: "threaded_post_id",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_chat_rooms_background_id",
table: "chat_rooms",
column: "background_id");
migrationBuilder.CreateIndex(
name: "ix_chat_rooms_picture_id",
table: "chat_rooms",
column: "picture_id");
migrationBuilder.CreateIndex(
name: "ix_account_profiles_background_id",
table: "account_profiles",
column: "background_id");
migrationBuilder.CreateIndex(
name: "ix_account_profiles_picture_id",
table: "account_profiles",
column: "picture_id");
migrationBuilder.AddForeignKey(
name: "fk_account_profiles_files_background_id",
table: "account_profiles",
column: "background_id",
principalTable: "files",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "fk_account_profiles_files_picture_id",
table: "account_profiles",
column: "picture_id",
principalTable: "files",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "fk_chat_rooms_files_background_id",
table: "chat_rooms",
column: "background_id",
principalTable: "files",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "fk_chat_rooms_files_picture_id",
table: "chat_rooms",
column: "picture_id",
principalTable: "files",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "fk_posts_posts_threaded_post_id",
table: "posts",
column: "threaded_post_id",
principalTable: "posts",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "fk_publishers_files_background_id",
table: "publishers",
column: "background_id",
principalTable: "files",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "fk_publishers_files_picture_id",
table: "publishers",
column: "picture_id",
principalTable: "files",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "fk_realms_files_background_id",
table: "realms",
column: "background_id",
principalTable: "files",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "fk_realms_files_picture_id",
table: "realms",
column: "picture_id",
principalTable: "files",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "fk_stickers_files_image_id",
table: "stickers",
column: "image_id",
principalTable: "files",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@ -1,38 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class FixPushNotificationIndex : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "ix_notification_push_subscriptions_device_token_device_id",
table: "notification_push_subscriptions");
migrationBuilder.CreateIndex(
name: "ix_notification_push_subscriptions_device_token_device_id_acco",
table: "notification_push_subscriptions",
columns: new[] { "device_token", "device_id", "account_id" },
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "ix_notification_push_subscriptions_device_token_device_id_acco",
table: "notification_push_subscriptions");
migrationBuilder.CreateIndex(
name: "ix_notification_push_subscriptions_device_token_device_id",
table: "notification_push_subscriptions",
columns: new[] { "device_token", "device_id" },
unique: true);
}
}
}

Some files were not shown because too many files have changed in this diff Show More