diff --git a/DysonNetwork.Sphere/Account/Account.cs b/DysonNetwork.Sphere/Account/Account.cs index f4d3937..1a56882 100644 --- a/DysonNetwork.Sphere/Account/Account.cs +++ b/DysonNetwork.Sphere/Account/Account.cs @@ -13,6 +13,7 @@ public class Account : ModelBase [MaxLength(256)] public string Name { get; set; } = string.Empty; [MaxLength(256)] public string Nick { get; set; } = string.Empty; [MaxLength(32)] public string Language { get; set; } = string.Empty; + public Instant? ActivatedAt { get; set; } public bool IsSuperuser { get; set; } = false; public Profile Profile { get; set; } = null!; @@ -24,8 +25,6 @@ public class Account : ModelBase [JsonIgnore] public ICollection OutgoingRelationships { get; set; } = new List(); [JsonIgnore] public ICollection IncomingRelationships { get; set; } = new List(); - - [JsonIgnore] public ICollection GroupMemberships { get; set; } = new List(); } public class Profile : ModelBase diff --git a/DysonNetwork.Sphere/Account/AccountController.cs b/DysonNetwork.Sphere/Account/AccountController.cs index 341705e..a3920d7 100644 --- a/DysonNetwork.Sphere/Account/AccountController.cs +++ b/DysonNetwork.Sphere/Account/AccountController.cs @@ -1,15 +1,23 @@ using System.ComponentModel.DataAnnotations; +using DysonNetwork.Sphere.Auth; using DysonNetwork.Sphere.Storage; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; +using NodaTime; namespace DysonNetwork.Sphere.Account; [ApiController] [Route("/accounts")] -public class AccountController(AppDatabase db, FileService fs, IMemoryCache memCache) : ControllerBase +public class AccountController( + AppDatabase db, + FileService fs, + AuthService auth, + MagicSpellService spells, + IMemoryCache memCache +) : ControllerBase { [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] @@ -39,6 +47,10 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC [MinLength(4)] [MaxLength(128)] public string Password { get; set; } = string.Empty; + + [MaxLength(128)] public string Language { get; set; } = "en"; + + [Required] public string CaptchaToken { get; set; } = string.Empty; } [HttpPost] @@ -46,6 +58,8 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task> CreateAccount([FromBody] AccountCreateRequest request) { + if (!await auth.ValidateCaptcha(request.CaptchaToken)) return BadRequest("Invalid captcha token."); + var dupeNameCount = await db.Accounts.Where(a => a.Name == request.Name).CountAsync(); if (dupeNameCount > 0) return BadRequest("The name is already taken."); @@ -54,6 +68,7 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC { Name = request.Name, Nick = request.Nick, + Language = request.Language, Contacts = new List { new() @@ -75,6 +90,18 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC await db.Accounts.AddAsync(account); await db.SaveChangesAsync(); + + var spell = await spells.CreateMagicSpell( + account, + MagicSpellType.AccountActivation, + new Dictionary + { + { "contact_method", account.Contacts.First().Content } + }, + expiredAt: SystemClock.Instance.GetCurrentInstant().Plus(Duration.FromDays(7)) + ); + spells.NotifyMagicSpell(spell); + return account; } @@ -110,7 +137,7 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC if (request.Nick is not null) account.Nick = request.Nick; if (request.Language is not null) account.Language = request.Language; - + memCache.Remove($"user_${account.Id}"); await db.SaveChangesAsync(); @@ -171,9 +198,9 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC db.Update(profile); await db.SaveChangesAsync(); - + memCache.Remove($"user_${userId}"); - + return profile; } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Account/AccountService.cs b/DysonNetwork.Sphere/Account/AccountService.cs index 5711621..9170da7 100644 --- a/DysonNetwork.Sphere/Account/AccountService.cs +++ b/DysonNetwork.Sphere/Account/AccountService.cs @@ -1,10 +1,11 @@ using Casbin; +using DysonNetwork.Sphere.Permission; using Microsoft.EntityFrameworkCore; using NodaTime; namespace DysonNetwork.Sphere.Account; -public class AccountService(AppDatabase db, IEnforcer enforcer) +public class AccountService(AppDatabase db, PermissionService pm) { public async Task LookupAccount(string probe) { @@ -145,18 +146,18 @@ public class AccountService(AppDatabase db, IEnforcer enforcer) // others: use the default permissions by design var domain = $"user:{relationship.AccountId.ToString()}"; - var target = relationship.RelatedId.ToString(); + var target = $"user:{relationship.RelatedId.ToString()}"; - await enforcer.DeleteRolesForUserAsync(target, domain); + await pm.RemovePermissionNode(target, domain, "*"); - string role = relationship.Status switch + bool? value = relationship.Status switch { - RelationshipStatus.Friends => "friends", - RelationshipStatus.Blocked => "blocked", - _ => "default" // fallback role + RelationshipStatus.Friends => true, + RelationshipStatus.Blocked => false, + _ => null, }; - if (role == "default") return; + if (value is null) return; - await enforcer.AddRoleForUserAsync(target, role, domain); + await pm.AddPermissionNode(target, domain, "*", value); } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Account/EmailService.cs b/DysonNetwork.Sphere/Account/EmailService.cs new file mode 100644 index 0000000..492c105 --- /dev/null +++ b/DysonNetwork.Sphere/Account/EmailService.cs @@ -0,0 +1,49 @@ +using MailKit.Net.Smtp; +using MimeKit; + +namespace DysonNetwork.Sphere.Account; + +public class EmailServiceConfiguration +{ + public string Server { get; set; } + public int Port { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public string FromAddress { get; set; } + public string FromName { get; set; } + public string SubjectPrefix { get; set; } +} + +public class EmailService +{ + private readonly EmailServiceConfiguration _configuration; + + public EmailService(IConfiguration configuration) + { + var cfg = configuration.GetValue("Email"); + _configuration = cfg ?? throw new ArgumentException("Email service was not configured."); + } + + public async Task SendEmailAsync(string? recipientName, string recipientEmail, string subject, string textBody) + { + subject = $"[{_configuration.SubjectPrefix}] {subject}"; + + var emailMessage = new MimeMessage(); + emailMessage.From.Add(new MailboxAddress(_configuration.FromName, _configuration.FromAddress)); + emailMessage.To.Add(new MailboxAddress(recipientName, recipientEmail)); + emailMessage.Subject = subject; + + var bodyBuilder = new BodyBuilder + { + TextBody = textBody + }; + + emailMessage.Body = bodyBuilder.ToMessageBody(); + + using var client = new SmtpClient(); + await client.ConnectAsync(_configuration.Server, _configuration.Port, true); + await client.AuthenticateAsync(_configuration.Username, _configuration.Password); + await client.SendAsync(emailMessage); + await client.DisconnectAsync(true); + } +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Account/MagicSpell.cs b/DysonNetwork.Sphere/Account/MagicSpell.cs new file mode 100644 index 0000000..286ea50 --- /dev/null +++ b/DysonNetwork.Sphere/Account/MagicSpell.cs @@ -0,0 +1,30 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; +using Microsoft.EntityFrameworkCore; +using NodaTime; + +namespace DysonNetwork.Sphere.Account; + +public enum MagicSpellType +{ + AccountActivation, + AccountDeactivation, + AccountRemoval, + AuthFactorReset, + ContactVerification, +} + +[Index(nameof(Spell), IsUnique = true)] +public class MagicSpell : ModelBase +{ + public Guid Id { get; set; } = Guid.NewGuid(); + [JsonIgnore] [MaxLength(1024)] public string Spell { get; set; } = null!; + public MagicSpellType Type { get; set; } + public Instant? ExpiresAt { get; set; } + public Instant? AffectedAt { get; set; } + [Column(TypeName = "jsonb")] public Dictionary Meta { get; set; } + + public long? AccountId { get; set; } + public Account? Account { get; set; } +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Account/MagicSpellService.cs b/DysonNetwork.Sphere/Account/MagicSpellService.cs new file mode 100644 index 0000000..98c35cc --- /dev/null +++ b/DysonNetwork.Sphere/Account/MagicSpellService.cs @@ -0,0 +1,122 @@ +using System.Security.Cryptography; +using DysonNetwork.Sphere.Permission; +using Microsoft.EntityFrameworkCore; +using NodaTime; + +namespace DysonNetwork.Sphere.Account; + +public class MagicSpellService(AppDatabase db, EmailService email, ILogger logger) +{ + public async Task CreateMagicSpell( + Account account, + MagicSpellType type, + Dictionary meta, + Instant? expiredAt = null, + Instant? affectedAt = null + ) + { + var spellWord = _GenerateRandomString(128); + var spell = new MagicSpell + { + Spell = spellWord, + Type = type, + ExpiresAt = expiredAt, + AffectedAt = affectedAt, + Account = account, + AccountId = account.Id, + Meta = meta + }; + + db.MagicSpells.Add(spell); + await db.SaveChangesAsync(); + + return spell; + } + + public async Task NotifyMagicSpell(MagicSpell spell, bool bypassVerify = false) + { + var contact = await db.AccountContacts + .Where(c => c.Account.Id == spell.AccountId) + .Where(c => c.Type == AccountContactType.Email) + .Where(c => c.VerifiedAt != null || bypassVerify) + .Include(c => c.Account) + .FirstOrDefaultAsync(); + if (contact is null) throw new ArgumentException("Account has no contact method that can use"); + + // TODO replace the baseurl + var link = $"https://api.sn.solsynth.dev/spells/{spell}"; + + try + { + switch (spell.Type) + { + case MagicSpellType.AccountActivation: + await email.SendEmailAsync( + contact.Account.Name, + contact.Content, + "Confirm your registration", + "Thank you for creating an account.\n" + + "For accessing all the features, confirm your registration with the link below:\n\n" + + $"{link}" + ); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + catch (Exception err) + { + logger.LogError($"Error sending magic spell (${spell.Spell})... {err}"); + } + } + + public async Task ApplyMagicSpell(MagicSpell spell) + { + switch (spell.Type) + { + case MagicSpellType.AccountActivation: + var contact = await + db.AccountContacts.FirstOrDefaultAsync(c => + c.Account.Id == spell.AccountId && c.Content == spell.Meta["contact_method"] as string + ); + if (contact is not null) + { + contact.VerifiedAt = SystemClock.Instance.GetCurrentInstant(); + db.Update(contact); + } + + var account = await db.Accounts.FirstOrDefaultAsync(c => c.Id == spell.AccountId); + if (account is not null) + { + account.ActivatedAt = SystemClock.Instance.GetCurrentInstant(); + db.Update(account); + } + + var defaultGroup = await db.PermissionGroups.FirstOrDefaultAsync(g => g.Key == "default"); + if (defaultGroup is not null && account is not null) + { + db.PermissionGroupMembers.Add(new PermissionGroupMember + { + Actor = $"user:{account.Id}", + Group = defaultGroup + }); + } + + await db.SaveChangesAsync(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private static string _GenerateRandomString(int length) + { + using var rng = RandomNumberGenerator.Create(); + var randomBytes = new byte[length]; + rng.GetBytes(randomBytes); + + var base64String = Convert.ToBase64String(randomBytes); + + return base64String.Substring(0, length); + } +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/AppDatabase.cs b/DysonNetwork.Sphere/AppDatabase.cs index 6126b80..ebcf170 100644 --- a/DysonNetwork.Sphere/AppDatabase.cs +++ b/DysonNetwork.Sphere/AppDatabase.cs @@ -1,4 +1,5 @@ using System.Linq.Expressions; +using DysonNetwork.Sphere.Permission; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using NodaTime; @@ -19,18 +20,24 @@ public class AppDatabase( IConfiguration configuration ) : DbContext(options) { - public DbSet PermissionNodes { get; set; } = null!; - public DbSet PermissionGroups { get; set; } = null!; + public DbSet PermissionNodes { get; set; } = null!; + public DbSet PermissionGroups { get; set; } = null!; + public DbSet PermissionGroupMembers { get; set; } = null!; + + public DbSet MagicSpells { get; set; } = null!; public DbSet Accounts { get; set; } public DbSet AccountProfiles { get; set; } public DbSet AccountContacts { get; set; } public DbSet AccountAuthFactors { get; set; } public DbSet AccountRelationships { get; set; } - public DbSet AuthSessions { get; set; } - public DbSet AuthChallenges { get; set; } public DbSet Notifications { get; set; } public DbSet NotificationPushSubscriptions { get; set; } + + public DbSet AuthSessions { get; set; } + public DbSet AuthChallenges { get; set; } + public DbSet Files { get; set; } + public DbSet Publishers { get; set; } public DbSet PublisherMembers { get; set; } public DbSet Posts { get; set; } @@ -51,6 +58,25 @@ public class AppDatabase( opt => opt.UseNodaTime() ).UseSnakeCaseNamingConvention(); + optionsBuilder.UseAsyncSeeding(async (context, _, cancellationToken) => + { + var defaultPermissionGroup = await context.Set() + .FirstOrDefaultAsync(g => g.Key == "default", cancellationToken); + if (defaultPermissionGroup is null) + { + context.Set().Add(new PermissionGroup + { + Key = "default", + Nodes = + { + PermissionService.NewPermissionNode("group:default", "global", "posts.create", true), + PermissionService.NewPermissionNode("group:default", "global", "publishers.create", true) + } + }); + await context.SaveChangesAsync(cancellationToken); + } + }); + base.OnConfiguring(optionsBuilder); } @@ -59,19 +85,13 @@ public class AppDatabase( base.OnModelCreating(modelBuilder); modelBuilder.Entity() - .HasKey(pg => new { pg.GroupId, pg.AccountId }) - .HasName("permission_group_members"); + .HasKey(pg => new { pg.GroupId, pg.Actor }); modelBuilder.Entity() .HasOne(pg => pg.Group) .WithMany(g => g.Members) .HasForeignKey(pg => pg.GroupId) .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .HasOne(pg => pg.Account) - .WithMany(a => a.GroupMemberships) - .HasForeignKey(pg => pg.AccountId) - .OnDelete(DeleteBehavior.Cascade); - + modelBuilder.Entity() .HasOne(a => a.Profile) .WithOne(p => p.Account) @@ -87,7 +107,7 @@ public class AppDatabase( .HasOne(r => r.Related) .WithMany(a => a.IncomingRelationships) .HasForeignKey(r => r.RelatedId); - + modelBuilder.Entity() .HasKey(pm => new { pm.PublisherId, pm.AccountId }); modelBuilder.Entity() @@ -100,7 +120,7 @@ public class AppDatabase( .WithMany() .HasForeignKey(pm => pm.AccountId) .OnDelete(DeleteBehavior.Cascade); - + modelBuilder.Entity() .HasOne(p => p.ThreadedPost) .WithOne() @@ -113,7 +133,7 @@ public class AppDatabase( modelBuilder.Entity() .HasOne(p => p.ForwardedPost) .WithMany() - .HasForeignKey(p => p.ForwardedPostId) + .HasForeignKey(p => p.ForwardedPostId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() .HasMany(p => p.Tags) diff --git a/DysonNetwork.Sphere/Auth/AuthController.cs b/DysonNetwork.Sphere/Auth/AuthController.cs index 739ca6f..7e4adcb 100644 --- a/DysonNetwork.Sphere/Auth/AuthController.cs +++ b/DysonNetwork.Sphere/Auth/AuthController.cs @@ -15,8 +15,7 @@ public class AuthController( AppDatabase db, AccountService accounts, AuthService auth, - IConfiguration configuration, - IHttpClientFactory httpClientFactory + IConfiguration configuration ) : ControllerBase { public class ChallengeRequest @@ -218,49 +217,7 @@ public class AuthController( [HttpPost("captcha")] public async Task ValidateCaptcha([FromBody] string token) { - var provider = configuration.GetSection("Captcha")["Provider"]?.ToLower(); - var apiKey = configuration.GetSection("Captcha")["ApiKey"]; - var apiSecret = configuration.GetSection("Captcha")["ApiSecret"]; - - var client = httpClientFactory.CreateClient(); - - switch (provider) - { - case "cloudflare": - var content = new StringContent($"secret={apiSecret}&response={token}", System.Text.Encoding.UTF8, - "application/x-www-form-urlencoded"); - var response = await client.PostAsync("https://challenges.cloudflare.com/turnstile/v0/siteverify", - content); - response.EnsureSuccessStatusCode(); - - var json = await response.Content.ReadAsStringAsync(); - var cfResult = JsonSerializer.Deserialize(json); - - if (cfResult?.Success == true) - return Ok(new { success = true }); - - return BadRequest(new { success = false, errors = cfResult?.ErrorCodes }); - case "google": - var secretKey = configuration.GetSection("CaptchaSettings")["GoogleRecaptchaSecretKey"]; - if (string.IsNullOrEmpty(secretKey)) - { - return StatusCode(500, "Google reCaptcha secret key is not configured."); - } - - content = new StringContent($"secret={secretKey}&response={token}", System.Text.Encoding.UTF8, - "application/x-www-form-urlencoded"); - response = await client.PostAsync("https://www.google.com/recaptcha/api/siteverify", content); - response.EnsureSuccessStatusCode(); - - json = await response.Content.ReadAsStringAsync(); - var capResult = JsonSerializer.Deserialize(json); - - if (capResult?.Success == true) - return Ok(new { success = true }); - - return BadRequest(new { success = false, errors = capResult?.ErrorCodes }); - default: - return StatusCode(500, "The server misconfigured for the captcha."); - } + var result = await auth.ValidateCaptcha(token); + return result ? Ok() : BadRequest(); } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Auth/AuthService.cs b/DysonNetwork.Sphere/Auth/AuthService.cs index c7023b3..b751c59 100644 --- a/DysonNetwork.Sphere/Auth/AuthService.cs +++ b/DysonNetwork.Sphere/Auth/AuthService.cs @@ -1,6 +1,7 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; +using System.Text.Json; using Casbin; using Microsoft.AspNetCore.Authorization; using Microsoft.IdentityModel.Tokens; @@ -15,68 +16,43 @@ public class SignedTokenPair public Instant ExpiredAt { get; set; } } -public class AuthService(AppDatabase db, IConfiguration config, IEnforcer enforcer) +public class AuthService(IConfiguration config, IHttpClientFactory httpClientFactory) { - public async Task AssignRoleToUserAsync(string user, string role, string domain = "global") + public async Task ValidateCaptcha(string token) { - var added = await enforcer.AddGroupingPolicyAsync(user, role, domain); - if (added) await enforcer.SavePolicyAsync(); - return added; - } + var provider = config.GetSection("Captcha")["Provider"]?.ToLower(); + var apiSecret = config.GetSection("Captcha")["ApiSecret"]; - public async Task AddPermissionToUserAsync(string user, string domain, string obj, string act) - { - var added = await enforcer.AddPolicyAsync(user, domain, obj, act); - if (added) await enforcer.SavePolicyAsync(); - return added; - } - - public async Task RemovePermissionFromUserAsync(string user, string domain, string obj, string act) - { - var removed = await enforcer.RemovePolicyAsync(user, domain, obj, act); - if (removed) await enforcer.SavePolicyAsync(); - return removed; - } + var client = httpClientFactory.CreateClient(); - public async Task CreateRoleAsync(string role, string domain, IEnumerable<(string obj, string act)> permissions) - { - bool anyAdded = false; - foreach (var (obj, act) in permissions) + switch (provider) { - var added = await enforcer.AddPolicyAsync(role, domain, obj, act); - if (added) anyAdded = true; - } + case "cloudflare": + var content = new StringContent($"secret={apiSecret}&response={token}", System.Text.Encoding.UTF8, + "application/x-www-form-urlencoded"); + var response = await client.PostAsync("https://challenges.cloudflare.com/turnstile/v0/siteverify", + content); + response.EnsureSuccessStatusCode(); - if (anyAdded) await enforcer.SavePolicyAsync(); - return anyAdded; + var json = await response.Content.ReadAsStringAsync(); + var cfResult = JsonSerializer.Deserialize(json); + + return cfResult?.Success == true; + case "google": + content = new StringContent($"secret={apiSecret}&response={token}", System.Text.Encoding.UTF8, + "application/x-www-form-urlencoded"); + response = await client.PostAsync("https://www.google.com/recaptcha/api/siteverify", content); + response.EnsureSuccessStatusCode(); + + json = await response.Content.ReadAsStringAsync(); + var capResult = JsonSerializer.Deserialize(json); + + return capResult?.Success == true; + default: + throw new ArgumentException("The server misconfigured for the captcha."); + } } - public async Task AddPermissionsToRoleAsync(string role, string domain, IEnumerable<(string obj, string act)> permissions) - { - bool anyAdded = false; - foreach (var (obj, act) in permissions) - { - var added = await enforcer.AddPolicyAsync(role, domain, obj, act); - if (added) anyAdded = true; - } - - if (anyAdded) await enforcer.SavePolicyAsync(); - return anyAdded; - } - - public async Task RemovePermissionsFromRoleAsync(string role, string domain, IEnumerable<(string obj, string act)> permissions) - { - bool anyRemoved = false; - foreach (var (obj, act) in permissions) - { - var removed = await enforcer.RemovePolicyAsync(role, domain, obj, act); - if (removed) anyRemoved = true; - } - - if (anyRemoved) await enforcer.SavePolicyAsync(); - return anyRemoved; - } - public SignedTokenPair CreateToken(Session session) { var privateKeyPem = File.ReadAllText(config["Jwt:PrivateKeyPath"]!); @@ -98,9 +74,9 @@ public class AuthService(AppDatabase db, IConfiguration config, IEnforcer enforc expires: DateTime.Now.AddDays(30), signingCredentials: creds ); - + session.Challenge.Scopes.ForEach(c => claims.Add(new Claim("scope", c))); - if(session.Account.IsSuperuser) claims.Add(new Claim("is_superuser", "1")); + if (session.Account.IsSuperuser) claims.Add(new Claim("is_superuser", "1")); var accessTokenClaims = new JwtSecurityToken( issuer: "solar-network", audience: string.Join(',', session.Challenge.Audiences), diff --git a/DysonNetwork.Sphere/Auth/CasbinRequirement.cs b/DysonNetwork.Sphere/Auth/CasbinRequirement.cs deleted file mode 100644 index 0e26bef..0000000 --- a/DysonNetwork.Sphere/Auth/CasbinRequirement.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Casbin; -using Microsoft.AspNetCore.Authorization; - -namespace DysonNetwork.Sphere.Auth; - -public class CasbinRequirement(string domain, string obj, string act) : IAuthorizationRequirement -{ - public string Domain { get; } = domain; - public string Object { get; } = obj; - public string Action { get; } = act; -} - -public class CasbinAuthorizationHandler(IEnforcer enforcer) - : AuthorizationHandler -{ - protected override async Task HandleRequirementAsync( - AuthorizationHandlerContext context, - CasbinRequirement requirement) - { - var userId = context.User.FindFirst("user_id")?.Value; - if (userId == null) return; - var isSuperuser = context.User.FindFirst("is_superuser")?.Value == "1"; - if (isSuperuser) userId = "super:" + userId; - - var allowed = await enforcer.EnforceAsync( - userId, - requirement.Domain, - requirement.Object, - requirement.Action - ); - - if (allowed) context.Succeed(requirement); - } -} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Auth/Session.cs b/DysonNetwork.Sphere/Auth/Session.cs index 508c414..fdc95da 100644 --- a/DysonNetwork.Sphere/Auth/Session.cs +++ b/DysonNetwork.Sphere/Auth/Session.cs @@ -21,6 +21,7 @@ public class Challenge : ModelBase public Instant? ExpiredAt { get; set; } public int StepRemain { get; set; } public int StepTotal { get; set; } + public int FailedAttempts { get; set; } [Column(TypeName = "jsonb")] public List BlacklistFactors { get; set; } = new(); [Column(TypeName = "jsonb")] public List Audiences { get; set; } = new(); [Column(TypeName = "jsonb")] public List Scopes { get; set; } = new(); diff --git a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj index 66bdb9c..bf0f9be 100644 --- a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj +++ b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj @@ -16,6 +16,7 @@ + diff --git a/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.Designer.cs b/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.Designer.cs deleted file mode 100644 index 47979e0..0000000 --- a/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.Designer.cs +++ /dev/null @@ -1,541 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Sphere; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250413115936_InitialMigration")] - partial class InitialMigration - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("IsSuperuser") - .HasColumnType("boolean") - .HasColumnName("is_superuser"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("language"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Nick") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("nick"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_accounts"); - - b.ToTable("accounts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Secret") - .HasColumnType("text") - .HasColumnName("secret"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_account_auth_factors"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_account_auth_factors_account_id"); - - b.ToTable("account_auth_factors", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("Content") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("content"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("VerifiedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("verified_at"); - - b.HasKey("Id") - .HasName("pk_account_contacts"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_account_contacts_account_id"); - - b.ToTable("account_contacts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("BackgroundId") - .HasColumnType("text") - .HasColumnName("background_id"); - - b.Property("Bio") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("bio"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("FirstName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("first_name"); - - b.Property("LastName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("last_name"); - - b.Property("MiddleName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("middle_name"); - - b.Property("PictureId") - .HasColumnType("text") - .HasColumnName("picture_id"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_account_profiles"); - - b.HasIndex("BackgroundId") - .HasDatabaseName("ix_account_profiles_background_id"); - - b.HasIndex("PictureId") - .HasDatabaseName("ix_account_profiles_picture_id"); - - b.ToTable("account_profiles", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property>("Audiences") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("audiences"); - - b.Property>("BlacklistFactors") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("blacklist_factors"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("DeviceId") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("device_id"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("IpAddress") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("ip_address"); - - b.Property("Nonce") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("nonce"); - - b.Property>("Scopes") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("scopes"); - - b.Property("StepRemain") - .HasColumnType("integer") - .HasColumnName("step_remain"); - - b.Property("StepTotal") - .HasColumnType("integer") - .HasColumnName("step_total"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UserAgent") - .HasMaxLength(512) - .HasColumnType("character varying(512)") - .HasColumnName("user_agent"); - - b.HasKey("Id") - .HasName("pk_auth_challenges"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_auth_challenges_account_id"); - - b.ToTable("auth_challenges", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("ChallengeId") - .HasColumnType("uuid") - .HasColumnName("challenge_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("LastGrantedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_granted_at"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_auth_sessions"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_auth_sessions_account_id"); - - b.HasIndex("ChallengeId") - .HasDatabaseName("ix_auth_sessions_challenge_id"); - - b.ToTable("auth_sessions", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => - { - b.Property("Id") - .HasColumnType("text") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property>("FileMeta") - .HasColumnType("jsonb") - .HasColumnName("file_meta"); - - b.Property("Hash") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("hash"); - - b.Property("MimeType") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("mime_type"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("Size") - .HasColumnType("bigint") - .HasColumnName("size"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("uploaded_at"); - - b.Property("UploadedTo") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("uploaded_to"); - - b.Property("UsedCount") - .HasColumnType("integer") - .HasColumnName("used_count"); - - b.Property>("UserMeta") - .HasColumnType("jsonb") - .HasColumnName("user_meta"); - - b.HasKey("Id") - .HasName("pk_files"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_files_account_id"); - - b.ToTable("files", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("AuthFactors") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_auth_factors_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Contacts") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_contacts_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => - { - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") - .WithMany() - .HasForeignKey("BackgroundId") - .HasConstraintName("fk_account_profiles_files_background_id"); - - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithOne("Profile") - .HasForeignKey("DysonNetwork.Sphere.Account.Profile", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_profiles_accounts_id"); - - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") - .WithMany() - .HasForeignKey("PictureId") - .HasConstraintName("fk_account_profiles_files_picture_id"); - - b.Navigation("Account"); - - b.Navigation("Background"); - - b.Navigation("Picture"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Challenges") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_challenges_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Sessions") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_sessions_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Auth.Challenge", "Challenge") - .WithMany() - .HasForeignKey("ChallengeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_sessions_auth_challenges_challenge_id"); - - b.Navigation("Account"); - - b.Navigation("Challenge"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_files_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => - { - b.Navigation("AuthFactors"); - - b.Navigation("Challenges"); - - b.Navigation("Contacts"); - - b.Navigation("Profile") - .IsRequired(); - - b.Navigation("Sessions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.cs b/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.cs deleted file mode 100644 index 9c883e5..0000000 --- a/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.cs +++ /dev/null @@ -1,279 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - /// - public partial class InitialMigration : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "accounts", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - nick = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - language = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - is_superuser = table.Column(type: "boolean", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_accounts", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "account_auth_factors", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - type = table.Column(type: "integer", nullable: false), - secret = table.Column(type: "text", nullable: true), - account_id = table.Column(type: "bigint", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_account_auth_factors", x => x.id); - table.ForeignKey( - name: "fk_account_auth_factors_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "account_contacts", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - type = table.Column(type: "integer", nullable: false), - verified_at = table.Column(type: "timestamp with time zone", nullable: true), - content = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), - account_id = table.Column(type: "bigint", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_account_contacts", x => x.id); - table.ForeignKey( - name: "fk_account_contacts_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "auth_challenges", - columns: table => new - { - id = table.Column(type: "uuid", nullable: false), - expired_at = table.Column(type: "timestamp with time zone", nullable: true), - step_remain = table.Column(type: "integer", nullable: false), - step_total = table.Column(type: "integer", nullable: false), - blacklist_factors = table.Column>(type: "jsonb", nullable: false), - audiences = table.Column>(type: "jsonb", nullable: false), - scopes = table.Column>(type: "jsonb", nullable: false), - ip_address = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), - user_agent = table.Column(type: "character varying(512)", maxLength: 512, nullable: true), - device_id = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - nonce = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), - account_id = table.Column(type: "bigint", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_auth_challenges", x => x.id); - table.ForeignKey( - name: "fk_auth_challenges_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "files", - columns: table => new - { - id = table.Column(type: "text", nullable: false), - name = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), - description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), - file_meta = table.Column>(type: "jsonb", nullable: true), - user_meta = table.Column>(type: "jsonb", nullable: true), - mime_type = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - hash = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - size = table.Column(type: "bigint", nullable: false), - uploaded_at = table.Column(type: "timestamp with time zone", nullable: true), - uploaded_to = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), - used_count = table.Column(type: "integer", nullable: false), - account_id = table.Column(type: "bigint", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_files", x => x.id); - table.ForeignKey( - name: "fk_files_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "auth_sessions", - columns: table => new - { - id = table.Column(type: "uuid", nullable: false), - last_granted_at = table.Column(type: "timestamp with time zone", nullable: true), - expired_at = table.Column(type: "timestamp with time zone", nullable: true), - account_id = table.Column(type: "bigint", nullable: false), - challenge_id = table.Column(type: "uuid", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_auth_sessions", x => x.id); - table.ForeignKey( - name: "fk_auth_sessions_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_auth_sessions_auth_challenges_challenge_id", - column: x => x.challenge_id, - principalTable: "auth_challenges", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "account_profiles", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false), - first_name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - middle_name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - last_name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - bio = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), - picture_id = table.Column(type: "text", nullable: true), - background_id = table.Column(type: "text", nullable: true), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_account_profiles", x => x.id); - table.ForeignKey( - name: "fk_account_profiles_accounts_id", - column: x => x.id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_account_profiles_files_background_id", - column: x => x.background_id, - principalTable: "files", - principalColumn: "id"); - table.ForeignKey( - name: "fk_account_profiles_files_picture_id", - column: x => x.picture_id, - principalTable: "files", - principalColumn: "id"); - }); - - migrationBuilder.CreateIndex( - name: "ix_account_auth_factors_account_id", - table: "account_auth_factors", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_account_contacts_account_id", - table: "account_contacts", - column: "account_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.CreateIndex( - name: "ix_auth_challenges_account_id", - table: "auth_challenges", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_auth_sessions_account_id", - table: "auth_sessions", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_auth_sessions_challenge_id", - table: "auth_sessions", - column: "challenge_id"); - - migrationBuilder.CreateIndex( - name: "ix_files_account_id", - table: "files", - column: "account_id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "account_auth_factors"); - - migrationBuilder.DropTable( - name: "account_contacts"); - - migrationBuilder.DropTable( - name: "account_profiles"); - - migrationBuilder.DropTable( - name: "auth_sessions"); - - migrationBuilder.DropTable( - name: "files"); - - migrationBuilder.DropTable( - name: "auth_challenges"); - - migrationBuilder.DropTable( - name: "accounts"); - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250417145426_AddRelationship.Designer.cs b/DysonNetwork.Sphere/Migrations/20250417145426_AddRelationship.Designer.cs deleted file mode 100644 index 7729f6f..0000000 --- a/DysonNetwork.Sphere/Migrations/20250417145426_AddRelationship.Designer.cs +++ /dev/null @@ -1,605 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Sphere; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250417145426_AddRelationship")] - partial class AddRelationship - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("IsSuperuser") - .HasColumnType("boolean") - .HasColumnName("is_superuser"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("language"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Nick") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("nick"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_accounts"); - - b.ToTable("accounts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Secret") - .HasColumnType("text") - .HasColumnName("secret"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_account_auth_factors"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_account_auth_factors_account_id"); - - b.ToTable("account_auth_factors", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("Content") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("content"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("VerifiedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("verified_at"); - - b.HasKey("Id") - .HasName("pk_account_contacts"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_account_contacts_account_id"); - - b.ToTable("account_contacts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("BackgroundId") - .HasColumnType("text") - .HasColumnName("background_id"); - - b.Property("Bio") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("bio"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("FirstName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("first_name"); - - b.Property("LastName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("last_name"); - - b.Property("MiddleName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("middle_name"); - - b.Property("PictureId") - .HasColumnType("text") - .HasColumnName("picture_id"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_account_profiles"); - - b.HasIndex("BackgroundId") - .HasDatabaseName("ix_account_profiles_background_id"); - - b.HasIndex("PictureId") - .HasDatabaseName("ix_account_profiles_picture_id"); - - b.ToTable("account_profiles", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => - { - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("RelatedId") - .HasColumnType("bigint") - .HasColumnName("related_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("Status") - .HasColumnType("integer") - .HasColumnName("status"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("AccountId", "RelatedId") - .HasName("pk_account_relationships"); - - b.HasIndex("RelatedId") - .HasDatabaseName("ix_account_relationships_related_id"); - - b.ToTable("account_relationships", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property>("Audiences") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("audiences"); - - b.Property>("BlacklistFactors") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("blacklist_factors"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("DeviceId") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("device_id"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("IpAddress") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("ip_address"); - - b.Property("Nonce") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("nonce"); - - b.Property>("Scopes") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("scopes"); - - b.Property("StepRemain") - .HasColumnType("integer") - .HasColumnName("step_remain"); - - b.Property("StepTotal") - .HasColumnType("integer") - .HasColumnName("step_total"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UserAgent") - .HasMaxLength(512) - .HasColumnType("character varying(512)") - .HasColumnName("user_agent"); - - b.HasKey("Id") - .HasName("pk_auth_challenges"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_auth_challenges_account_id"); - - b.ToTable("auth_challenges", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("ChallengeId") - .HasColumnType("uuid") - .HasColumnName("challenge_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("LastGrantedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_granted_at"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_auth_sessions"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_auth_sessions_account_id"); - - b.HasIndex("ChallengeId") - .HasDatabaseName("ix_auth_sessions_challenge_id"); - - b.ToTable("auth_sessions", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => - { - b.Property("Id") - .HasColumnType("text") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property>("FileMeta") - .HasColumnType("jsonb") - .HasColumnName("file_meta"); - - b.Property("Hash") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("hash"); - - b.Property("MimeType") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("mime_type"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("Size") - .HasColumnType("bigint") - .HasColumnName("size"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("uploaded_at"); - - b.Property("UploadedTo") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("uploaded_to"); - - b.Property("UsedCount") - .HasColumnType("integer") - .HasColumnName("used_count"); - - b.Property>("UserMeta") - .HasColumnType("jsonb") - .HasColumnName("user_meta"); - - b.HasKey("Id") - .HasName("pk_files"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_files_account_id"); - - b.ToTable("files", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("AuthFactors") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_auth_factors_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Contacts") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_contacts_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => - { - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") - .WithMany() - .HasForeignKey("BackgroundId") - .HasConstraintName("fk_account_profiles_files_background_id"); - - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithOne("Profile") - .HasForeignKey("DysonNetwork.Sphere.Account.Profile", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_profiles_accounts_id"); - - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") - .WithMany() - .HasForeignKey("PictureId") - .HasConstraintName("fk_account_profiles_files_picture_id"); - - b.Navigation("Account"); - - b.Navigation("Background"); - - b.Navigation("Picture"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("OutgoingRelationships") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_relationships_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Account.Account", "Related") - .WithMany("IncomingRelationships") - .HasForeignKey("RelatedId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_relationships_accounts_related_id"); - - b.Navigation("Account"); - - b.Navigation("Related"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Challenges") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_challenges_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Sessions") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_sessions_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Auth.Challenge", "Challenge") - .WithMany() - .HasForeignKey("ChallengeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_sessions_auth_challenges_challenge_id"); - - b.Navigation("Account"); - - b.Navigation("Challenge"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_files_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => - { - b.Navigation("AuthFactors"); - - b.Navigation("Challenges"); - - b.Navigation("Contacts"); - - b.Navigation("IncomingRelationships"); - - b.Navigation("OutgoingRelationships"); - - b.Navigation("Profile") - .IsRequired(); - - b.Navigation("Sessions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250417145426_AddRelationship.cs b/DysonNetwork.Sphere/Migrations/20250417145426_AddRelationship.cs deleted file mode 100644 index 6ef0141..0000000 --- a/DysonNetwork.Sphere/Migrations/20250417145426_AddRelationship.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - /// - public partial class AddRelationship : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "account_relationships", - columns: table => new - { - account_id = table.Column(type: "bigint", nullable: false), - related_id = table.Column(type: "bigint", nullable: false), - expired_at = table.Column(type: "timestamp with time zone", nullable: true), - status = table.Column(type: "integer", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_account_relationships", x => new { x.account_id, x.related_id }); - table.ForeignKey( - name: "fk_account_relationships_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_account_relationships_accounts_related_id", - column: x => x.related_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_account_relationships_related_id", - table: "account_relationships", - column: "related_id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "account_relationships"); - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250419115230_AddPost.Designer.cs b/DysonNetwork.Sphere/Migrations/20250419115230_AddPost.Designer.cs deleted file mode 100644 index 79b4916..0000000 --- a/DysonNetwork.Sphere/Migrations/20250419115230_AddPost.Designer.cs +++ /dev/null @@ -1,1258 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Sphere; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250419115230_AddPost")] - partial class AddPost - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("IsSuperuser") - .HasColumnType("boolean") - .HasColumnName("is_superuser"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("language"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Nick") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("nick"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_accounts"); - - b.HasIndex("Name") - .IsUnique() - .HasDatabaseName("ix_accounts_name"); - - b.ToTable("accounts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Secret") - .HasColumnType("text") - .HasColumnName("secret"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_account_auth_factors"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_account_auth_factors_account_id"); - - b.ToTable("account_auth_factors", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("Content") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("content"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("VerifiedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("verified_at"); - - b.HasKey("Id") - .HasName("pk_account_contacts"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_account_contacts_account_id"); - - b.ToTable("account_contacts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("BackgroundId") - .HasColumnType("text") - .HasColumnName("background_id"); - - b.Property("Bio") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("bio"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("FirstName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("first_name"); - - b.Property("LastName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("last_name"); - - b.Property("MiddleName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("middle_name"); - - b.Property("PictureId") - .HasColumnType("text") - .HasColumnName("picture_id"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_account_profiles"); - - b.HasIndex("BackgroundId") - .HasDatabaseName("ix_account_profiles_background_id"); - - b.HasIndex("PictureId") - .HasDatabaseName("ix_account_profiles_picture_id"); - - b.ToTable("account_profiles", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => - { - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("RelatedId") - .HasColumnType("bigint") - .HasColumnName("related_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("Status") - .HasColumnType("integer") - .HasColumnName("status"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("AccountId", "RelatedId") - .HasName("pk_account_relationships"); - - b.HasIndex("RelatedId") - .HasDatabaseName("ix_account_relationships_related_id"); - - b.ToTable("account_relationships", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property>("Audiences") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("audiences"); - - b.Property>("BlacklistFactors") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("blacklist_factors"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("DeviceId") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("device_id"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("IpAddress") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("ip_address"); - - b.Property("Nonce") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("nonce"); - - b.Property>("Scopes") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("scopes"); - - b.Property("StepRemain") - .HasColumnType("integer") - .HasColumnName("step_remain"); - - b.Property("StepTotal") - .HasColumnType("integer") - .HasColumnName("step_total"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UserAgent") - .HasMaxLength(512) - .HasColumnType("character varying(512)") - .HasColumnName("user_agent"); - - b.HasKey("Id") - .HasName("pk_auth_challenges"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_auth_challenges_account_id"); - - b.ToTable("auth_challenges", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("ChallengeId") - .HasColumnType("uuid") - .HasColumnName("challenge_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("LastGrantedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_granted_at"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_auth_sessions"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_auth_sessions_account_id"); - - b.HasIndex("ChallengeId") - .HasDatabaseName("ix_auth_sessions_challenge_id"); - - b.ToTable("auth_sessions", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Content") - .HasColumnType("text") - .HasColumnName("content"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property("Downvotes") - .HasColumnType("integer") - .HasColumnName("downvotes"); - - b.Property("EditedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("edited_at"); - - b.Property("ForwardedPostId") - .HasColumnType("bigint") - .HasColumnName("forwarded_post_id"); - - b.Property("Language") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("language"); - - b.Property>("Meta") - .HasColumnType("jsonb") - .HasColumnName("meta"); - - b.Property("PublishedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("published_at"); - - b.Property("PublisherId") - .HasColumnType("bigint") - .HasColumnName("publisher_id"); - - b.Property("RepliedPostId") - .HasColumnType("bigint") - .HasColumnName("replied_post_id"); - - b.Property("ThreadedPostId") - .HasColumnType("bigint") - .HasColumnName("threaded_post_id"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("title"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Upvotes") - .HasColumnType("integer") - .HasColumnName("upvotes"); - - b.Property("ViewsTotal") - .HasColumnType("integer") - .HasColumnName("views_total"); - - b.Property("ViewsUnique") - .HasColumnType("integer") - .HasColumnName("views_unique"); - - b.Property("Visibility") - .HasColumnType("integer") - .HasColumnName("visibility"); - - b.HasKey("Id") - .HasName("pk_posts"); - - b.HasIndex("ForwardedPostId") - .HasDatabaseName("ix_posts_forwarded_post_id"); - - b.HasIndex("PublisherId") - .HasDatabaseName("ix_posts_publisher_id"); - - b.HasIndex("RepliedPostId") - .HasDatabaseName("ix_posts_replied_post_id"); - - b.HasIndex("ThreadedPostId") - .IsUnique() - .HasDatabaseName("ix_posts_threaded_post_id"); - - b.ToTable("posts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCategory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("slug"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_post_categories"); - - b.ToTable("post_categories", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCollection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("PublisherId") - .HasColumnType("bigint") - .HasColumnName("publisher_id"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("slug"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_post_collections"); - - b.HasIndex("PublisherId") - .HasDatabaseName("ix_post_collections_publisher_id"); - - b.ToTable("post_collections", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostReaction", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("Attitude") - .HasColumnType("integer") - .HasColumnName("attitude"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("PostId") - .HasColumnType("bigint") - .HasColumnName("post_id"); - - b.Property("Symbol") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("symbol"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_post_reactions"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_post_reactions_account_id"); - - b.HasIndex("PostId") - .HasDatabaseName("ix_post_reactions_post_id"); - - b.ToTable("post_reactions", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostTag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("slug"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_post_tags"); - - b.ToTable("post_tags", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("BackgroundId") - .HasColumnType("text") - .HasColumnName("background_id"); - - b.Property("Bio") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("bio"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Nick") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("nick"); - - b.Property("PictureId") - .HasColumnType("text") - .HasColumnName("picture_id"); - - b.Property("PublisherType") - .HasColumnType("integer") - .HasColumnName("publisher_type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_publishers"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_publishers_account_id"); - - b.HasIndex("BackgroundId") - .HasDatabaseName("ix_publishers_background_id"); - - b.HasIndex("Name") - .IsUnique() - .HasDatabaseName("ix_publishers_name"); - - b.HasIndex("PictureId") - .HasDatabaseName("ix_publishers_picture_id"); - - b.ToTable("publishers", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherMember", b => - { - b.Property("PublisherId") - .HasColumnType("bigint") - .HasColumnName("publisher_id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("JoinedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("joined_at"); - - b.Property("Role") - .HasColumnType("integer") - .HasColumnName("role"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("PublisherId", "AccountId") - .HasName("pk_publisher_members"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_publisher_members_account_id"); - - b.ToTable("publisher_members", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => - { - b.Property("Id") - .HasColumnType("text") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property>("FileMeta") - .HasColumnType("jsonb") - .HasColumnName("file_meta"); - - b.Property("Hash") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("hash"); - - b.Property("MimeType") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("mime_type"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("PostId") - .HasColumnType("bigint") - .HasColumnName("post_id"); - - b.Property("Size") - .HasColumnType("bigint") - .HasColumnName("size"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("uploaded_at"); - - b.Property("UploadedTo") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("uploaded_to"); - - b.Property("UsedCount") - .HasColumnType("integer") - .HasColumnName("used_count"); - - b.Property>("UserMeta") - .HasColumnType("jsonb") - .HasColumnName("user_meta"); - - b.HasKey("Id") - .HasName("pk_files"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_files_account_id"); - - b.HasIndex("PostId") - .HasDatabaseName("ix_files_post_id"); - - b.ToTable("files", (string)null); - }); - - modelBuilder.Entity("PostPostCategory", b => - { - b.Property("CategoriesId") - .HasColumnType("bigint") - .HasColumnName("categories_id"); - - b.Property("PostsId") - .HasColumnType("bigint") - .HasColumnName("posts_id"); - - b.HasKey("CategoriesId", "PostsId") - .HasName("pk_post_category_links"); - - b.HasIndex("PostsId") - .HasDatabaseName("ix_post_category_links_posts_id"); - - b.ToTable("post_category_links", (string)null); - }); - - modelBuilder.Entity("PostPostCollection", b => - { - b.Property("CollectionsId") - .HasColumnType("bigint") - .HasColumnName("collections_id"); - - b.Property("PostsId") - .HasColumnType("bigint") - .HasColumnName("posts_id"); - - b.HasKey("CollectionsId", "PostsId") - .HasName("pk_post_collection_links"); - - b.HasIndex("PostsId") - .HasDatabaseName("ix_post_collection_links_posts_id"); - - b.ToTable("post_collection_links", (string)null); - }); - - modelBuilder.Entity("PostPostTag", b => - { - b.Property("PostsId") - .HasColumnType("bigint") - .HasColumnName("posts_id"); - - b.Property("TagsId") - .HasColumnType("bigint") - .HasColumnName("tags_id"); - - b.HasKey("PostsId", "TagsId") - .HasName("pk_post_tag_links"); - - b.HasIndex("TagsId") - .HasDatabaseName("ix_post_tag_links_tags_id"); - - b.ToTable("post_tag_links", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("AuthFactors") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_auth_factors_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Contacts") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_contacts_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => - { - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") - .WithMany() - .HasForeignKey("BackgroundId") - .HasConstraintName("fk_account_profiles_files_background_id"); - - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithOne("Profile") - .HasForeignKey("DysonNetwork.Sphere.Account.Profile", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_profiles_accounts_id"); - - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") - .WithMany() - .HasForeignKey("PictureId") - .HasConstraintName("fk_account_profiles_files_picture_id"); - - b.Navigation("Account"); - - b.Navigation("Background"); - - b.Navigation("Picture"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("OutgoingRelationships") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_relationships_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Account.Account", "Related") - .WithMany("IncomingRelationships") - .HasForeignKey("RelatedId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_relationships_accounts_related_id"); - - b.Navigation("Account"); - - b.Navigation("Related"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Challenges") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_challenges_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Sessions") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_sessions_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Auth.Challenge", "Challenge") - .WithMany() - .HasForeignKey("ChallengeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_sessions_auth_challenges_challenge_id"); - - b.Navigation("Account"); - - b.Navigation("Challenge"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => - { - b.HasOne("DysonNetwork.Sphere.Post.Post", "ForwardedPost") - .WithMany() - .HasForeignKey("ForwardedPostId") - .OnDelete(DeleteBehavior.Restrict) - .HasConstraintName("fk_posts_posts_forwarded_post_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") - .WithMany("Posts") - .HasForeignKey("PublisherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_posts_publishers_publisher_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", "RepliedPost") - .WithMany() - .HasForeignKey("RepliedPostId") - .OnDelete(DeleteBehavior.Restrict) - .HasConstraintName("fk_posts_posts_replied_post_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", "ThreadedPost") - .WithOne() - .HasForeignKey("DysonNetwork.Sphere.Post.Post", "ThreadedPostId") - .HasConstraintName("fk_posts_posts_threaded_post_id"); - - b.Navigation("ForwardedPost"); - - b.Navigation("Publisher"); - - b.Navigation("RepliedPost"); - - b.Navigation("ThreadedPost"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCollection", b => - { - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") - .WithMany("Collections") - .HasForeignKey("PublisherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_collections_publishers_publisher_id"); - - b.Navigation("Publisher"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostReaction", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_reactions_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", "Post") - .WithMany("Reactions") - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_reactions_posts_post_id"); - - b.Navigation("Account"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .HasConstraintName("fk_publishers_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") - .WithMany() - .HasForeignKey("BackgroundId") - .HasConstraintName("fk_publishers_files_background_id"); - - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") - .WithMany() - .HasForeignKey("PictureId") - .HasConstraintName("fk_publishers_files_picture_id"); - - b.Navigation("Account"); - - b.Navigation("Background"); - - b.Navigation("Picture"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherMember", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_publisher_members_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") - .WithMany("Members") - .HasForeignKey("PublisherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_publisher_members_publishers_publisher_id"); - - b.Navigation("Account"); - - b.Navigation("Publisher"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_files_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", null) - .WithMany("Attachments") - .HasForeignKey("PostId") - .HasConstraintName("fk_files_posts_post_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("PostPostCategory", b => - { - b.HasOne("DysonNetwork.Sphere.Post.PostCategory", null) - .WithMany() - .HasForeignKey("CategoriesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_category_links_post_categories_categories_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", null) - .WithMany() - .HasForeignKey("PostsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_category_links_posts_posts_id"); - }); - - modelBuilder.Entity("PostPostCollection", b => - { - b.HasOne("DysonNetwork.Sphere.Post.PostCollection", null) - .WithMany() - .HasForeignKey("CollectionsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_collection_links_post_collections_collections_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", null) - .WithMany() - .HasForeignKey("PostsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_collection_links_posts_posts_id"); - }); - - modelBuilder.Entity("PostPostTag", b => - { - b.HasOne("DysonNetwork.Sphere.Post.Post", null) - .WithMany() - .HasForeignKey("PostsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_tag_links_posts_posts_id"); - - b.HasOne("DysonNetwork.Sphere.Post.PostTag", null) - .WithMany() - .HasForeignKey("TagsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_tag_links_post_tags_tags_id"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => - { - b.Navigation("AuthFactors"); - - b.Navigation("Challenges"); - - b.Navigation("Contacts"); - - b.Navigation("IncomingRelationships"); - - b.Navigation("OutgoingRelationships"); - - b.Navigation("Profile") - .IsRequired(); - - b.Navigation("Sessions"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => - { - b.Navigation("Attachments"); - - b.Navigation("Reactions"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => - { - b.Navigation("Collections"); - - b.Navigation("Members"); - - b.Navigation("Posts"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250419115230_AddPost.cs b/DysonNetwork.Sphere/Migrations/20250419115230_AddPost.cs deleted file mode 100644 index 79c7714..0000000 --- a/DysonNetwork.Sphere/Migrations/20250419115230_AddPost.cs +++ /dev/null @@ -1,451 +0,0 @@ -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - /// - public partial class AddPost : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "post_id", - table: "files", - type: "bigint", - nullable: true); - - migrationBuilder.CreateTable( - name: "post_categories", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), - name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_post_categories", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "post_tags", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), - name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_post_tags", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "publishers", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - publisher_type = table.Column(type: "integer", nullable: false), - name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - nick = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - bio = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), - picture_id = table.Column(type: "text", nullable: true), - background_id = table.Column(type: "text", nullable: true), - account_id = table.Column(type: "bigint", nullable: true), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_publishers", x => x.id); - table.ForeignKey( - name: "fk_publishers_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id"); - table.ForeignKey( - name: "fk_publishers_files_background_id", - column: x => x.background_id, - principalTable: "files", - principalColumn: "id"); - table.ForeignKey( - name: "fk_publishers_files_picture_id", - column: x => x.picture_id, - principalTable: "files", - principalColumn: "id"); - }); - - migrationBuilder.CreateTable( - name: "post_collections", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), - name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), - publisher_id = table.Column(type: "bigint", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_post_collections", x => x.id); - table.ForeignKey( - name: "fk_post_collections_publishers_publisher_id", - column: x => x.publisher_id, - principalTable: "publishers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "posts", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - title = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), - description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), - language = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), - edited_at = table.Column(type: "timestamp with time zone", nullable: true), - published_at = table.Column(type: "timestamp with time zone", nullable: true), - visibility = table.Column(type: "integer", nullable: false), - content = table.Column(type: "text", nullable: true), - type = table.Column(type: "integer", nullable: false), - meta = table.Column>(type: "jsonb", nullable: true), - views_unique = table.Column(type: "integer", nullable: false), - views_total = table.Column(type: "integer", nullable: false), - upvotes = table.Column(type: "integer", nullable: false), - downvotes = table.Column(type: "integer", nullable: false), - threaded_post_id = table.Column(type: "bigint", nullable: true), - replied_post_id = table.Column(type: "bigint", nullable: true), - forwarded_post_id = table.Column(type: "bigint", nullable: true), - publisher_id = table.Column(type: "bigint", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_posts", x => x.id); - table.ForeignKey( - name: "fk_posts_posts_forwarded_post_id", - column: x => x.forwarded_post_id, - principalTable: "posts", - principalColumn: "id", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "fk_posts_posts_replied_post_id", - column: x => x.replied_post_id, - principalTable: "posts", - principalColumn: "id", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "fk_posts_posts_threaded_post_id", - column: x => x.threaded_post_id, - principalTable: "posts", - principalColumn: "id"); - table.ForeignKey( - name: "fk_posts_publishers_publisher_id", - column: x => x.publisher_id, - principalTable: "publishers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "publisher_members", - columns: table => new - { - publisher_id = table.Column(type: "bigint", nullable: false), - account_id = table.Column(type: "bigint", nullable: false), - role = table.Column(type: "integer", nullable: false), - joined_at = table.Column(type: "timestamp with time zone", nullable: true), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_publisher_members", x => new { x.publisher_id, x.account_id }); - table.ForeignKey( - name: "fk_publisher_members_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_publisher_members_publishers_publisher_id", - column: x => x.publisher_id, - principalTable: "publishers", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "post_category_links", - columns: table => new - { - categories_id = table.Column(type: "bigint", nullable: false), - posts_id = table.Column(type: "bigint", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_post_category_links", x => new { x.categories_id, x.posts_id }); - table.ForeignKey( - name: "fk_post_category_links_post_categories_categories_id", - column: x => x.categories_id, - principalTable: "post_categories", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_post_category_links_posts_posts_id", - column: x => x.posts_id, - principalTable: "posts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "post_collection_links", - columns: table => new - { - collections_id = table.Column(type: "bigint", nullable: false), - posts_id = table.Column(type: "bigint", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_post_collection_links", x => new { x.collections_id, x.posts_id }); - table.ForeignKey( - name: "fk_post_collection_links_post_collections_collections_id", - column: x => x.collections_id, - principalTable: "post_collections", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_post_collection_links_posts_posts_id", - column: x => x.posts_id, - principalTable: "posts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "post_reactions", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - symbol = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - attitude = table.Column(type: "integer", nullable: false), - post_id = table.Column(type: "bigint", nullable: false), - account_id = table.Column(type: "bigint", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_post_reactions", x => x.id); - table.ForeignKey( - name: "fk_post_reactions_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_post_reactions_posts_post_id", - column: x => x.post_id, - principalTable: "posts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "post_tag_links", - columns: table => new - { - posts_id = table.Column(type: "bigint", nullable: false), - tags_id = table.Column(type: "bigint", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_post_tag_links", x => new { x.posts_id, x.tags_id }); - table.ForeignKey( - name: "fk_post_tag_links_post_tags_tags_id", - column: x => x.tags_id, - principalTable: "post_tags", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_post_tag_links_posts_posts_id", - column: x => x.posts_id, - principalTable: "posts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_files_post_id", - table: "files", - column: "post_id"); - - migrationBuilder.CreateIndex( - name: "ix_accounts_name", - table: "accounts", - column: "name", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_post_category_links_posts_id", - table: "post_category_links", - column: "posts_id"); - - migrationBuilder.CreateIndex( - name: "ix_post_collection_links_posts_id", - table: "post_collection_links", - column: "posts_id"); - - migrationBuilder.CreateIndex( - name: "ix_post_collections_publisher_id", - table: "post_collections", - column: "publisher_id"); - - migrationBuilder.CreateIndex( - name: "ix_post_reactions_account_id", - table: "post_reactions", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_post_reactions_post_id", - table: "post_reactions", - column: "post_id"); - - migrationBuilder.CreateIndex( - name: "ix_post_tag_links_tags_id", - table: "post_tag_links", - column: "tags_id"); - - migrationBuilder.CreateIndex( - name: "ix_posts_forwarded_post_id", - table: "posts", - column: "forwarded_post_id"); - - migrationBuilder.CreateIndex( - name: "ix_posts_publisher_id", - table: "posts", - column: "publisher_id"); - - migrationBuilder.CreateIndex( - name: "ix_posts_replied_post_id", - table: "posts", - column: "replied_post_id"); - - migrationBuilder.CreateIndex( - name: "ix_posts_threaded_post_id", - table: "posts", - column: "threaded_post_id", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_publisher_members_account_id", - table: "publisher_members", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_publishers_account_id", - table: "publishers", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_publishers_background_id", - table: "publishers", - column: "background_id"); - - migrationBuilder.CreateIndex( - name: "ix_publishers_name", - table: "publishers", - column: "name", - unique: true); - - migrationBuilder.CreateIndex( - name: "ix_publishers_picture_id", - table: "publishers", - column: "picture_id"); - - migrationBuilder.AddForeignKey( - name: "fk_files_posts_post_id", - table: "files", - column: "post_id", - principalTable: "posts", - principalColumn: "id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "fk_files_posts_post_id", - table: "files"); - - migrationBuilder.DropTable( - name: "post_category_links"); - - migrationBuilder.DropTable( - name: "post_collection_links"); - - migrationBuilder.DropTable( - name: "post_reactions"); - - migrationBuilder.DropTable( - name: "post_tag_links"); - - migrationBuilder.DropTable( - name: "publisher_members"); - - migrationBuilder.DropTable( - name: "post_categories"); - - migrationBuilder.DropTable( - name: "post_collections"); - - migrationBuilder.DropTable( - name: "post_tags"); - - migrationBuilder.DropTable( - name: "posts"); - - migrationBuilder.DropTable( - name: "publishers"); - - migrationBuilder.DropIndex( - name: "ix_files_post_id", - table: "files"); - - migrationBuilder.DropIndex( - name: "ix_accounts_name", - table: "accounts"); - - migrationBuilder.DropColumn( - name: "post_id", - table: "files"); - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250427154356_AddNotification.Designer.cs b/DysonNetwork.Sphere/Migrations/20250427154356_AddNotification.Designer.cs deleted file mode 100644 index 814e2b0..0000000 --- a/DysonNetwork.Sphere/Migrations/20250427154356_AddNotification.Designer.cs +++ /dev/null @@ -1,1406 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Sphere; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250427154356_AddNotification")] - partial class AddNotification - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("IsSuperuser") - .HasColumnType("boolean") - .HasColumnName("is_superuser"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("language"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Nick") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("nick"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_accounts"); - - b.HasIndex("Name") - .IsUnique() - .HasDatabaseName("ix_accounts_name"); - - b.ToTable("accounts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Secret") - .HasColumnType("text") - .HasColumnName("secret"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_account_auth_factors"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_account_auth_factors_account_id"); - - b.ToTable("account_auth_factors", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("Content") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("content"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("VerifiedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("verified_at"); - - b.HasKey("Id") - .HasName("pk_account_contacts"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_account_contacts_account_id"); - - b.ToTable("account_contacts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("Content") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("content"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property>("Meta") - .HasColumnType("jsonb") - .HasColumnName("meta"); - - b.Property("Priority") - .HasColumnType("integer") - .HasColumnName("priority"); - - b.Property("Subtitle") - .HasMaxLength(2048) - .HasColumnType("character varying(2048)") - .HasColumnName("subtitle"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("title"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("ViewedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("viewed_at"); - - b.HasKey("Id") - .HasName("pk_notifications"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_notifications_account_id"); - - b.ToTable("notifications", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.NotificationPushSubscription", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("DeviceId") - .IsRequired() - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("device_id"); - - b.Property("DeviceToken") - .IsRequired() - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("device_token"); - - b.Property("LastUsedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_used_at"); - - b.Property("Provider") - .HasColumnType("integer") - .HasColumnName("provider"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_notification_push_subscriptions"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_notification_push_subscriptions_account_id"); - - b.HasIndex("DeviceId") - .IsUnique() - .HasDatabaseName("ix_notification_push_subscriptions_device_id"); - - b.HasIndex("DeviceToken") - .IsUnique() - .HasDatabaseName("ix_notification_push_subscriptions_device_token"); - - b.ToTable("notification_push_subscriptions", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("BackgroundId") - .HasColumnType("character varying(128)") - .HasColumnName("background_id"); - - b.Property("Bio") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("bio"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("FirstName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("first_name"); - - b.Property("LastName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("last_name"); - - b.Property("MiddleName") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("middle_name"); - - b.Property("PictureId") - .HasColumnType("character varying(128)") - .HasColumnName("picture_id"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_account_profiles"); - - b.HasIndex("BackgroundId") - .HasDatabaseName("ix_account_profiles_background_id"); - - b.HasIndex("PictureId") - .HasDatabaseName("ix_account_profiles_picture_id"); - - b.ToTable("account_profiles", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => - { - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("RelatedId") - .HasColumnType("bigint") - .HasColumnName("related_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("Status") - .HasColumnType("integer") - .HasColumnName("status"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("AccountId", "RelatedId") - .HasName("pk_account_relationships"); - - b.HasIndex("RelatedId") - .HasDatabaseName("ix_account_relationships_related_id"); - - b.ToTable("account_relationships", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property>("Audiences") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("audiences"); - - b.Property>("BlacklistFactors") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("blacklist_factors"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("DeviceId") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("device_id"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("IpAddress") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("ip_address"); - - b.Property("Nonce") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("nonce"); - - b.Property>("Scopes") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("scopes"); - - b.Property("StepRemain") - .HasColumnType("integer") - .HasColumnName("step_remain"); - - b.Property("StepTotal") - .HasColumnType("integer") - .HasColumnName("step_total"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UserAgent") - .HasMaxLength(512) - .HasColumnType("character varying(512)") - .HasColumnName("user_agent"); - - b.HasKey("Id") - .HasName("pk_auth_challenges"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_auth_challenges_account_id"); - - b.ToTable("auth_challenges", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("ChallengeId") - .HasColumnType("uuid") - .HasColumnName("challenge_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("LastGrantedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_granted_at"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_auth_sessions"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_auth_sessions_account_id"); - - b.HasIndex("ChallengeId") - .HasDatabaseName("ix_auth_sessions_challenge_id"); - - b.ToTable("auth_sessions", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Content") - .HasColumnType("text") - .HasColumnName("content"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property("Downvotes") - .HasColumnType("integer") - .HasColumnName("downvotes"); - - b.Property("EditedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("edited_at"); - - b.Property("ForwardedPostId") - .HasColumnType("bigint") - .HasColumnName("forwarded_post_id"); - - b.Property("Language") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("language"); - - b.Property>("Meta") - .HasColumnType("jsonb") - .HasColumnName("meta"); - - b.Property("PublishedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("published_at"); - - b.Property("PublisherId") - .HasColumnType("bigint") - .HasColumnName("publisher_id"); - - b.Property("RepliedPostId") - .HasColumnType("bigint") - .HasColumnName("replied_post_id"); - - b.Property("ThreadedPostId") - .HasColumnType("bigint") - .HasColumnName("threaded_post_id"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("title"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Upvotes") - .HasColumnType("integer") - .HasColumnName("upvotes"); - - b.Property("ViewsTotal") - .HasColumnType("integer") - .HasColumnName("views_total"); - - b.Property("ViewsUnique") - .HasColumnType("integer") - .HasColumnName("views_unique"); - - b.Property("Visibility") - .HasColumnType("integer") - .HasColumnName("visibility"); - - b.HasKey("Id") - .HasName("pk_posts"); - - b.HasIndex("ForwardedPostId") - .HasDatabaseName("ix_posts_forwarded_post_id"); - - b.HasIndex("PublisherId") - .HasDatabaseName("ix_posts_publisher_id"); - - b.HasIndex("RepliedPostId") - .HasDatabaseName("ix_posts_replied_post_id"); - - b.HasIndex("ThreadedPostId") - .IsUnique() - .HasDatabaseName("ix_posts_threaded_post_id"); - - b.ToTable("posts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCategory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("slug"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_post_categories"); - - b.ToTable("post_categories", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCollection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("PublisherId") - .HasColumnType("bigint") - .HasColumnName("publisher_id"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("slug"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_post_collections"); - - b.HasIndex("PublisherId") - .HasDatabaseName("ix_post_collections_publisher_id"); - - b.ToTable("post_collections", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostReaction", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("Attitude") - .HasColumnType("integer") - .HasColumnName("attitude"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("PostId") - .HasColumnType("bigint") - .HasColumnName("post_id"); - - b.Property("Symbol") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("symbol"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_post_reactions"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_post_reactions_account_id"); - - b.HasIndex("PostId") - .HasDatabaseName("ix_post_reactions_post_id"); - - b.ToTable("post_reactions", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostTag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("slug"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_post_tags"); - - b.ToTable("post_tags", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("BackgroundId") - .HasColumnType("character varying(128)") - .HasColumnName("background_id"); - - b.Property("Bio") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("bio"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("name"); - - b.Property("Nick") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("nick"); - - b.Property("PictureId") - .HasColumnType("character varying(128)") - .HasColumnName("picture_id"); - - b.Property("PublisherType") - .HasColumnType("integer") - .HasColumnName("publisher_type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_publishers"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_publishers_account_id"); - - b.HasIndex("BackgroundId") - .HasDatabaseName("ix_publishers_background_id"); - - b.HasIndex("Name") - .IsUnique() - .HasDatabaseName("ix_publishers_name"); - - b.HasIndex("PictureId") - .HasDatabaseName("ix_publishers_picture_id"); - - b.ToTable("publishers", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherMember", b => - { - b.Property("PublisherId") - .HasColumnType("bigint") - .HasColumnName("publisher_id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("JoinedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("joined_at"); - - b.Property("Role") - .HasColumnType("integer") - .HasColumnName("role"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("PublisherId", "AccountId") - .HasName("pk_publisher_members"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_publisher_members_account_id"); - - b.ToTable("publisher_members", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => - { - b.Property("Id") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property>("FileMeta") - .HasColumnType("jsonb") - .HasColumnName("file_meta"); - - b.Property("Hash") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("hash"); - - b.Property("MimeType") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("mime_type"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("PostId") - .HasColumnType("bigint") - .HasColumnName("post_id"); - - b.Property("Size") - .HasColumnType("bigint") - .HasColumnName("size"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("uploaded_at"); - - b.Property("UploadedTo") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("uploaded_to"); - - b.Property("UsedCount") - .HasColumnType("integer") - .HasColumnName("used_count"); - - b.Property>("UserMeta") - .HasColumnType("jsonb") - .HasColumnName("user_meta"); - - b.HasKey("Id") - .HasName("pk_files"); - - b.HasIndex("AccountId") - .HasDatabaseName("ix_files_account_id"); - - b.HasIndex("PostId") - .HasDatabaseName("ix_files_post_id"); - - b.ToTable("files", (string)null); - }); - - modelBuilder.Entity("PostPostCategory", b => - { - b.Property("CategoriesId") - .HasColumnType("bigint") - .HasColumnName("categories_id"); - - b.Property("PostsId") - .HasColumnType("bigint") - .HasColumnName("posts_id"); - - b.HasKey("CategoriesId", "PostsId") - .HasName("pk_post_category_links"); - - b.HasIndex("PostsId") - .HasDatabaseName("ix_post_category_links_posts_id"); - - b.ToTable("post_category_links", (string)null); - }); - - modelBuilder.Entity("PostPostCollection", b => - { - b.Property("CollectionsId") - .HasColumnType("bigint") - .HasColumnName("collections_id"); - - b.Property("PostsId") - .HasColumnType("bigint") - .HasColumnName("posts_id"); - - b.HasKey("CollectionsId", "PostsId") - .HasName("pk_post_collection_links"); - - b.HasIndex("PostsId") - .HasDatabaseName("ix_post_collection_links_posts_id"); - - b.ToTable("post_collection_links", (string)null); - }); - - modelBuilder.Entity("PostPostTag", b => - { - b.Property("PostsId") - .HasColumnType("bigint") - .HasColumnName("posts_id"); - - b.Property("TagsId") - .HasColumnType("bigint") - .HasColumnName("tags_id"); - - b.HasKey("PostsId", "TagsId") - .HasName("pk_post_tag_links"); - - b.HasIndex("TagsId") - .HasDatabaseName("ix_post_tag_links_tags_id"); - - b.ToTable("post_tag_links", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("AuthFactors") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_auth_factors_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Contacts") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_contacts_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_notifications_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.NotificationPushSubscription", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_notification_push_subscriptions_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => - { - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") - .WithMany() - .HasForeignKey("BackgroundId") - .HasConstraintName("fk_account_profiles_files_background_id"); - - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithOne("Profile") - .HasForeignKey("DysonNetwork.Sphere.Account.Profile", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_profiles_accounts_id"); - - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") - .WithMany() - .HasForeignKey("PictureId") - .HasConstraintName("fk_account_profiles_files_picture_id"); - - b.Navigation("Account"); - - b.Navigation("Background"); - - b.Navigation("Picture"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("OutgoingRelationships") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_relationships_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Account.Account", "Related") - .WithMany("IncomingRelationships") - .HasForeignKey("RelatedId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_account_relationships_accounts_related_id"); - - b.Navigation("Account"); - - b.Navigation("Related"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Challenges") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_challenges_accounts_account_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("Sessions") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_sessions_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Auth.Challenge", "Challenge") - .WithMany() - .HasForeignKey("ChallengeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_sessions_auth_challenges_challenge_id"); - - b.Navigation("Account"); - - b.Navigation("Challenge"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => - { - b.HasOne("DysonNetwork.Sphere.Post.Post", "ForwardedPost") - .WithMany() - .HasForeignKey("ForwardedPostId") - .OnDelete(DeleteBehavior.Restrict) - .HasConstraintName("fk_posts_posts_forwarded_post_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") - .WithMany("Posts") - .HasForeignKey("PublisherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_posts_publishers_publisher_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", "RepliedPost") - .WithMany() - .HasForeignKey("RepliedPostId") - .OnDelete(DeleteBehavior.Restrict) - .HasConstraintName("fk_posts_posts_replied_post_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", "ThreadedPost") - .WithOne() - .HasForeignKey("DysonNetwork.Sphere.Post.Post", "ThreadedPostId") - .HasConstraintName("fk_posts_posts_threaded_post_id"); - - b.Navigation("ForwardedPost"); - - b.Navigation("Publisher"); - - b.Navigation("RepliedPost"); - - b.Navigation("ThreadedPost"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCollection", b => - { - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") - .WithMany("Collections") - .HasForeignKey("PublisherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_collections_publishers_publisher_id"); - - b.Navigation("Publisher"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PostReaction", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_reactions_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", "Post") - .WithMany("Reactions") - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_reactions_posts_post_id"); - - b.Navigation("Account"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .HasConstraintName("fk_publishers_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") - .WithMany() - .HasForeignKey("BackgroundId") - .HasConstraintName("fk_publishers_files_background_id"); - - b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") - .WithMany() - .HasForeignKey("PictureId") - .HasConstraintName("fk_publishers_files_picture_id"); - - b.Navigation("Account"); - - b.Navigation("Background"); - - b.Navigation("Picture"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherMember", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_publisher_members_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") - .WithMany("Members") - .HasForeignKey("PublisherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_publisher_members_publishers_publisher_id"); - - b.Navigation("Account"); - - b.Navigation("Publisher"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => - { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany() - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_files_accounts_account_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", null) - .WithMany("Attachments") - .HasForeignKey("PostId") - .HasConstraintName("fk_files_posts_post_id"); - - b.Navigation("Account"); - }); - - modelBuilder.Entity("PostPostCategory", b => - { - b.HasOne("DysonNetwork.Sphere.Post.PostCategory", null) - .WithMany() - .HasForeignKey("CategoriesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_category_links_post_categories_categories_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", null) - .WithMany() - .HasForeignKey("PostsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_category_links_posts_posts_id"); - }); - - modelBuilder.Entity("PostPostCollection", b => - { - b.HasOne("DysonNetwork.Sphere.Post.PostCollection", null) - .WithMany() - .HasForeignKey("CollectionsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_collection_links_post_collections_collections_id"); - - b.HasOne("DysonNetwork.Sphere.Post.Post", null) - .WithMany() - .HasForeignKey("PostsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_collection_links_posts_posts_id"); - }); - - modelBuilder.Entity("PostPostTag", b => - { - b.HasOne("DysonNetwork.Sphere.Post.Post", null) - .WithMany() - .HasForeignKey("PostsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_tag_links_posts_posts_id"); - - b.HasOne("DysonNetwork.Sphere.Post.PostTag", null) - .WithMany() - .HasForeignKey("TagsId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_post_tag_links_post_tags_tags_id"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => - { - b.Navigation("AuthFactors"); - - b.Navigation("Challenges"); - - b.Navigation("Contacts"); - - b.Navigation("IncomingRelationships"); - - b.Navigation("OutgoingRelationships"); - - b.Navigation("Profile") - .IsRequired(); - - b.Navigation("Sessions"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => - { - b.Navigation("Attachments"); - - b.Navigation("Reactions"); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => - { - b.Navigation("Collections"); - - b.Navigation("Members"); - - b.Navigation("Posts"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250427154356_AddNotification.cs b/DysonNetwork.Sphere/Migrations/20250427154356_AddNotification.cs deleted file mode 100644 index 40db3bb..0000000 --- a/DysonNetwork.Sphere/Migrations/20250427154356_AddNotification.cs +++ /dev/null @@ -1,201 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - /// - public partial class AddNotification : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "picture_id", - table: "publishers", - type: "character varying(128)", - nullable: true, - oldClrType: typeof(string), - oldType: "text", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "background_id", - table: "publishers", - type: "character varying(128)", - nullable: true, - oldClrType: typeof(string), - oldType: "text", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "id", - table: "files", - type: "character varying(128)", - maxLength: 128, - nullable: false, - oldClrType: typeof(string), - oldType: "text"); - - migrationBuilder.AddColumn( - name: "expired_at", - table: "files", - type: "timestamp with time zone", - nullable: true); - - migrationBuilder.AlterColumn( - name: "picture_id", - table: "account_profiles", - type: "character varying(128)", - nullable: true, - oldClrType: typeof(string), - oldType: "text", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "background_id", - table: "account_profiles", - type: "character varying(128)", - nullable: true, - oldClrType: typeof(string), - oldType: "text", - oldNullable: true); - - migrationBuilder.CreateTable( - name: "notification_push_subscriptions", - columns: table => new - { - id = table.Column(type: "uuid", nullable: false), - device_id = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: false), - device_token = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: false), - provider = table.Column(type: "integer", nullable: false), - last_used_at = table.Column(type: "timestamp with time zone", nullable: true), - account_id = table.Column(type: "bigint", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_notification_push_subscriptions", x => x.id); - table.ForeignKey( - name: "fk_notification_push_subscriptions_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "notifications", - columns: table => new - { - id = table.Column(type: "uuid", nullable: false), - title = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), - subtitle = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: true), - content = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), - meta = table.Column>(type: "jsonb", nullable: true), - priority = table.Column(type: "integer", nullable: false), - viewed_at = table.Column(type: "timestamp with time zone", nullable: true), - account_id = table.Column(type: "bigint", nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_notifications", x => x.id); - table.ForeignKey( - name: "fk_notifications_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_notification_push_subscriptions_account_id", - table: "notification_push_subscriptions", - column: "account_id"); - - 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); - - migrationBuilder.CreateIndex( - name: "ix_notifications_account_id", - table: "notifications", - column: "account_id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "notification_push_subscriptions"); - - migrationBuilder.DropTable( - name: "notifications"); - - migrationBuilder.DropColumn( - name: "expired_at", - table: "files"); - - migrationBuilder.AlterColumn( - name: "picture_id", - table: "publishers", - type: "text", - nullable: true, - oldClrType: typeof(string), - oldType: "character varying(128)", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "background_id", - table: "publishers", - type: "text", - nullable: true, - oldClrType: typeof(string), - oldType: "character varying(128)", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "id", - table: "files", - type: "text", - nullable: false, - oldClrType: typeof(string), - oldType: "character varying(128)", - oldMaxLength: 128); - - migrationBuilder.AlterColumn( - name: "picture_id", - table: "account_profiles", - type: "text", - nullable: true, - oldClrType: typeof(string), - oldType: "character varying(128)", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "background_id", - table: "account_profiles", - type: "text", - nullable: true, - oldClrType: typeof(string), - oldType: "character varying(128)", - oldNullable: true); - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250427161252_AddPermission.cs b/DysonNetwork.Sphere/Migrations/20250427161252_AddPermission.cs deleted file mode 100644 index a5cc131..0000000 --- a/DysonNetwork.Sphere/Migrations/20250427161252_AddPermission.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - /// - public partial class AddPermission : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "topic", - table: "notifications", - type: "character varying(1024)", - maxLength: 1024, - nullable: false, - defaultValue: ""); - - migrationBuilder.CreateTable( - name: "permission_groups", - columns: table => new - { - id = table.Column(type: "uuid", nullable: false), - key = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_permission_groups", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "permission_group_member", - columns: table => new - { - group_id = table.Column(type: "uuid", nullable: false), - account_id = table.Column(type: "bigint", nullable: false), - expired_at = table.Column(type: "timestamp with time zone", nullable: true), - affected_at = table.Column(type: "timestamp with time zone", nullable: true), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_permission_group_member", x => new { x.group_id, x.account_id }); - table.ForeignKey( - name: "fk_permission_group_member_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_permission_group_member_permission_groups_group_id", - column: x => x.group_id, - principalTable: "permission_groups", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "permission_nodes", - columns: table => new - { - id = table.Column(type: "uuid", nullable: false), - actor = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), - area = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), - key = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), - value = table.Column(type: "jsonb", nullable: false), - expired_at = table.Column(type: "timestamp with time zone", nullable: true), - affected_at = table.Column(type: "timestamp with time zone", nullable: true), - group_id = table.Column(type: "uuid", nullable: true), - permission_group_id = table.Column(type: "uuid", nullable: true), - created_at = table.Column(type: "timestamp with time zone", nullable: false), - updated_at = table.Column(type: "timestamp with time zone", nullable: false), - deleted_at = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_permission_nodes", x => x.id); - table.ForeignKey( - name: "fk_permission_nodes_permission_groups_permission_group_id", - column: x => x.permission_group_id, - principalTable: "permission_groups", - principalColumn: "id"); - table.ForeignKey( - name: "fk_permission_nodes_permission_nodes_group_id", - column: x => x.group_id, - principalTable: "permission_nodes", - principalColumn: "id"); - }); - - migrationBuilder.CreateIndex( - name: "ix_permission_group_member_account_id", - table: "permission_group_member", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_permission_nodes_group_id", - table: "permission_nodes", - column: "group_id"); - - migrationBuilder.CreateIndex( - name: "ix_permission_nodes_key_area_actor", - table: "permission_nodes", - columns: new[] { "key", "area", "actor" }); - - migrationBuilder.CreateIndex( - name: "ix_permission_nodes_permission_group_id", - table: "permission_nodes", - column: "permission_group_id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "permission_group_member"); - - migrationBuilder.DropTable( - name: "permission_nodes"); - - migrationBuilder.DropTable( - name: "permission_groups"); - - migrationBuilder.DropColumn( - name: "topic", - table: "notifications"); - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250427161252_AddPermission.Designer.cs b/DysonNetwork.Sphere/Migrations/20250429115700_InitialMigration.Designer.cs similarity index 95% rename from DysonNetwork.Sphere/Migrations/20250427161252_AddPermission.Designer.cs rename to DysonNetwork.Sphere/Migrations/20250429115700_InitialMigration.Designer.cs index 8587b82..29109ef 100644 --- a/DysonNetwork.Sphere/Migrations/20250427161252_AddPermission.Designer.cs +++ b/DysonNetwork.Sphere/Migrations/20250429115700_InitialMigration.Designer.cs @@ -1,6 +1,7 @@ // using System; using System.Collections.Generic; +using System.Text.Json; using DysonNetwork.Sphere; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -14,8 +15,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace DysonNetwork.Sphere.Migrations { [DbContext(typeof(AppDatabase))] - [Migration("20250427161252_AddPermission")] - partial class AddPermission + [Migration("20250429115700_InitialMigration")] + partial class InitialMigration { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -36,6 +37,10 @@ namespace DysonNetwork.Sphere.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("ActivatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("activated_at"); + b.Property("CreatedAt") .HasColumnType("timestamp with time zone") .HasColumnName("created_at"); @@ -170,6 +175,65 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("account_contacts", (string)null); }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("bigint") + .HasColumnName("account_id"); + + b.Property("AffectedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("affected_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires_at"); + + b.Property>("Meta") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("Spell") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("spell"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_magic_spells"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_magic_spells_account_id"); + + b.HasIndex("Spell") + .IsUnique() + .HasDatabaseName("ix_magic_spells_spell"); + + b.ToTable("magic_spells", (string)null); + }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => { b.Property("Id") @@ -430,6 +494,10 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("expired_at"); + b.Property("FailedAttempts") + .HasColumnType("integer") + .HasColumnName("failed_attempts"); + b.Property("IpAddress") .HasMaxLength(128) .HasColumnType("character varying(128)") @@ -555,9 +623,10 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("group_id"); - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); + b.Property("Actor") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("actor"); b.Property("AffectedAt") .HasColumnType("timestamp with time zone") @@ -579,13 +648,10 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("updated_at"); - b.HasKey("GroupId", "AccountId") - .HasName("pk_permission_group_member"); + b.HasKey("GroupId", "Actor") + .HasName("pk_permission_group_members"); - b.HasIndex("AccountId") - .HasDatabaseName("ix_permission_group_member_account_id"); - - b.ToTable("permission_group_member", (string)null); + b.ToTable("permission_group_members", (string)null); }); modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b => @@ -633,15 +699,11 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(1024)") .HasColumnName("key"); - b.Property("PermissionGroupId") - .HasColumnType("uuid") - .HasColumnName("permission_group_id"); - b.Property("UpdatedAt") .HasColumnType("timestamp with time zone") .HasColumnName("updated_at"); - b.Property("Value") + b.Property("Value") .IsRequired() .HasColumnType("jsonb") .HasColumnName("value"); @@ -652,9 +714,6 @@ namespace DysonNetwork.Sphere.Migrations b.HasIndex("GroupId") .HasDatabaseName("ix_permission_nodes_group_id"); - b.HasIndex("PermissionGroupId") - .HasDatabaseName("ix_permission_nodes_permission_group_id"); - b.HasIndex("Key", "Area", "Actor") .HasDatabaseName("ix_permission_nodes_key_area_actor"); @@ -1231,6 +1290,16 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Account"); }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .HasConstraintName("fk_magic_spells_accounts_account_id"); + + b.Navigation("Account"); + }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => { b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") @@ -1337,36 +1406,22 @@ namespace DysonNetwork.Sphere.Migrations modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroupMember", b => { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("GroupMemberships") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_permission_group_member_accounts_account_id"); - b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group") .WithMany("Members") .HasForeignKey("GroupId") .OnDelete(DeleteBehavior.Cascade) .IsRequired() - .HasConstraintName("fk_permission_group_member_permission_groups_group_id"); - - b.Navigation("Account"); + .HasConstraintName("fk_permission_group_members_permission_groups_group_id"); b.Navigation("Group"); }); modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b => { - b.HasOne("DysonNetwork.Sphere.Permission.PermissionNode", "Group") - .WithMany() - .HasForeignKey("GroupId") - .HasConstraintName("fk_permission_nodes_permission_nodes_group_id"); - - b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", null) + b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group") .WithMany("Nodes") - .HasForeignKey("PermissionGroupId") - .HasConstraintName("fk_permission_nodes_permission_groups_permission_group_id"); + .HasForeignKey("GroupId") + .HasConstraintName("fk_permission_nodes_permission_groups_group_id"); b.Navigation("Group"); }); @@ -1560,8 +1615,6 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Contacts"); - b.Navigation("GroupMemberships"); - b.Navigation("IncomingRelationships"); b.Navigation("OutgoingRelationships"); diff --git a/DysonNetwork.Sphere/Migrations/20250429115700_InitialMigration.cs b/DysonNetwork.Sphere/Migrations/20250429115700_InitialMigration.cs new file mode 100644 index 0000000..ccce33d --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20250429115700_InitialMigration.cs @@ -0,0 +1,952 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Microsoft.EntityFrameworkCore.Migrations; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace DysonNetwork.Sphere.Migrations +{ + /// + public partial class InitialMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "accounts", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + nick = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + language = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + activated_at = table.Column(type: "timestamp with time zone", nullable: true), + is_superuser = table.Column(type: "boolean", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_accounts", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "permission_groups", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + key = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_permission_groups", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "post_categories", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_post_categories", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "post_tags", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_post_tags", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "account_auth_factors", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + type = table.Column(type: "integer", nullable: false), + secret = table.Column(type: "text", nullable: true), + account_id = table.Column(type: "bigint", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_account_auth_factors", x => x.id); + table.ForeignKey( + name: "fk_account_auth_factors_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "account_contacts", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + type = table.Column(type: "integer", nullable: false), + verified_at = table.Column(type: "timestamp with time zone", nullable: true), + content = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + account_id = table.Column(type: "bigint", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_account_contacts", x => x.id); + table.ForeignKey( + name: "fk_account_contacts_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "account_relationships", + columns: table => new + { + account_id = table.Column(type: "bigint", nullable: false), + related_id = table.Column(type: "bigint", nullable: false), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + status = table.Column(type: "integer", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_account_relationships", x => new { x.account_id, x.related_id }); + table.ForeignKey( + name: "fk_account_relationships_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_account_relationships_accounts_related_id", + column: x => x.related_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "auth_challenges", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + step_remain = table.Column(type: "integer", nullable: false), + step_total = table.Column(type: "integer", nullable: false), + failed_attempts = table.Column(type: "integer", nullable: false), + blacklist_factors = table.Column>(type: "jsonb", nullable: false), + audiences = table.Column>(type: "jsonb", nullable: false), + scopes = table.Column>(type: "jsonb", nullable: false), + ip_address = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), + user_agent = table.Column(type: "character varying(512)", maxLength: 512, nullable: true), + device_id = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + nonce = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), + account_id = table.Column(type: "bigint", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_auth_challenges", x => x.id); + table.ForeignKey( + name: "fk_auth_challenges_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "magic_spells", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + spell = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + type = table.Column(type: "integer", nullable: false), + expires_at = table.Column(type: "timestamp with time zone", nullable: true), + affected_at = table.Column(type: "timestamp with time zone", nullable: true), + meta = table.Column>(type: "jsonb", nullable: false), + account_id = table.Column(type: "bigint", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_magic_spells", x => x.id); + table.ForeignKey( + name: "fk_magic_spells_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id"); + }); + + migrationBuilder.CreateTable( + name: "notification_push_subscriptions", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + device_id = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: false), + device_token = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: false), + provider = table.Column(type: "integer", nullable: false), + last_used_at = table.Column(type: "timestamp with time zone", nullable: true), + account_id = table.Column(type: "bigint", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_notification_push_subscriptions", x => x.id); + table.ForeignKey( + name: "fk_notification_push_subscriptions_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "notifications", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + topic = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + title = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), + subtitle = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: true), + content = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + meta = table.Column>(type: "jsonb", nullable: true), + priority = table.Column(type: "integer", nullable: false), + viewed_at = table.Column(type: "timestamp with time zone", nullable: true), + account_id = table.Column(type: "bigint", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_notifications", x => x.id); + table.ForeignKey( + name: "fk_notifications_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "permission_group_members", + columns: table => new + { + group_id = table.Column(type: "uuid", nullable: false), + actor = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + affected_at = table.Column(type: "timestamp with time zone", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_permission_group_members", x => new { x.group_id, x.actor }); + table.ForeignKey( + name: "fk_permission_group_members_permission_groups_group_id", + column: x => x.group_id, + principalTable: "permission_groups", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "permission_nodes", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + actor = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + area = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + key = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + value = table.Column(type: "jsonb", nullable: false), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + affected_at = table.Column(type: "timestamp with time zone", nullable: true), + group_id = table.Column(type: "uuid", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_permission_nodes", x => x.id); + table.ForeignKey( + name: "fk_permission_nodes_permission_groups_group_id", + column: x => x.group_id, + principalTable: "permission_groups", + principalColumn: "id"); + }); + + migrationBuilder.CreateTable( + name: "auth_sessions", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + last_granted_at = table.Column(type: "timestamp with time zone", nullable: true), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + account_id = table.Column(type: "bigint", nullable: false), + challenge_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_auth_sessions", x => x.id); + table.ForeignKey( + name: "fk_auth_sessions_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_auth_sessions_auth_challenges_challenge_id", + column: x => x.challenge_id, + principalTable: "auth_challenges", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "account_profiles", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false), + first_name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + middle_name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + last_name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + bio = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + picture_id = table.Column(type: "character varying(128)", nullable: true), + background_id = table.Column(type: "character varying(128)", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_account_profiles", x => x.id); + table.ForeignKey( + name: "fk_account_profiles_accounts_id", + column: x => x.id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "files", + columns: table => new + { + id = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + name = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + file_meta = table.Column>(type: "jsonb", nullable: true), + user_meta = table.Column>(type: "jsonb", nullable: true), + mime_type = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + hash = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + size = table.Column(type: "bigint", nullable: false), + uploaded_at = table.Column(type: "timestamp with time zone", nullable: true), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + uploaded_to = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), + used_count = table.Column(type: "integer", nullable: false), + account_id = table.Column(type: "bigint", nullable: false), + post_id = table.Column(type: "bigint", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_files", x => x.id); + table.ForeignKey( + name: "fk_files_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "publishers", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + publisher_type = table.Column(type: "integer", nullable: false), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + nick = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + bio = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + picture_id = table.Column(type: "character varying(128)", nullable: true), + background_id = table.Column(type: "character varying(128)", nullable: true), + account_id = table.Column(type: "bigint", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_publishers", x => x.id); + table.ForeignKey( + name: "fk_publishers_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id"); + table.ForeignKey( + name: "fk_publishers_files_background_id", + column: x => x.background_id, + principalTable: "files", + principalColumn: "id"); + table.ForeignKey( + name: "fk_publishers_files_picture_id", + column: x => x.picture_id, + principalTable: "files", + principalColumn: "id"); + }); + + migrationBuilder.CreateTable( + name: "post_collections", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + publisher_id = table.Column(type: "bigint", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_post_collections", x => x.id); + table.ForeignKey( + name: "fk_post_collections_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "posts", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + title = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + language = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), + edited_at = table.Column(type: "timestamp with time zone", nullable: true), + published_at = table.Column(type: "timestamp with time zone", nullable: true), + visibility = table.Column(type: "integer", nullable: false), + content = table.Column(type: "text", nullable: true), + type = table.Column(type: "integer", nullable: false), + meta = table.Column>(type: "jsonb", nullable: true), + views_unique = table.Column(type: "integer", nullable: false), + views_total = table.Column(type: "integer", nullable: false), + upvotes = table.Column(type: "integer", nullable: false), + downvotes = table.Column(type: "integer", nullable: false), + threaded_post_id = table.Column(type: "bigint", nullable: true), + replied_post_id = table.Column(type: "bigint", nullable: true), + forwarded_post_id = table.Column(type: "bigint", nullable: true), + publisher_id = table.Column(type: "bigint", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_posts", x => x.id); + table.ForeignKey( + name: "fk_posts_posts_forwarded_post_id", + column: x => x.forwarded_post_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "fk_posts_posts_replied_post_id", + column: x => x.replied_post_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "fk_posts_posts_threaded_post_id", + column: x => x.threaded_post_id, + principalTable: "posts", + principalColumn: "id"); + table.ForeignKey( + name: "fk_posts_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "publisher_members", + columns: table => new + { + publisher_id = table.Column(type: "bigint", nullable: false), + account_id = table.Column(type: "bigint", nullable: false), + role = table.Column(type: "integer", nullable: false), + joined_at = table.Column(type: "timestamp with time zone", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_publisher_members", x => new { x.publisher_id, x.account_id }); + table.ForeignKey( + name: "fk_publisher_members_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_publisher_members_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "post_category_links", + columns: table => new + { + categories_id = table.Column(type: "bigint", nullable: false), + posts_id = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_post_category_links", x => new { x.categories_id, x.posts_id }); + table.ForeignKey( + name: "fk_post_category_links_post_categories_categories_id", + column: x => x.categories_id, + principalTable: "post_categories", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_post_category_links_posts_posts_id", + column: x => x.posts_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "post_collection_links", + columns: table => new + { + collections_id = table.Column(type: "bigint", nullable: false), + posts_id = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_post_collection_links", x => new { x.collections_id, x.posts_id }); + table.ForeignKey( + name: "fk_post_collection_links_post_collections_collections_id", + column: x => x.collections_id, + principalTable: "post_collections", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_post_collection_links_posts_posts_id", + column: x => x.posts_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "post_reactions", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + symbol = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + attitude = table.Column(type: "integer", nullable: false), + post_id = table.Column(type: "bigint", nullable: false), + account_id = table.Column(type: "bigint", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_post_reactions", x => x.id); + table.ForeignKey( + name: "fk_post_reactions_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_post_reactions_posts_post_id", + column: x => x.post_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "post_tag_links", + columns: table => new + { + posts_id = table.Column(type: "bigint", nullable: false), + tags_id = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_post_tag_links", x => new { x.posts_id, x.tags_id }); + table.ForeignKey( + name: "fk_post_tag_links_post_tags_tags_id", + column: x => x.tags_id, + principalTable: "post_tags", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_post_tag_links_posts_posts_id", + column: x => x.posts_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_account_auth_factors_account_id", + table: "account_auth_factors", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_account_contacts_account_id", + table: "account_contacts", + column: "account_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.CreateIndex( + name: "ix_account_relationships_related_id", + table: "account_relationships", + column: "related_id"); + + migrationBuilder.CreateIndex( + name: "ix_accounts_name", + table: "accounts", + column: "name", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_auth_challenges_account_id", + table: "auth_challenges", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_auth_sessions_account_id", + table: "auth_sessions", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_auth_sessions_challenge_id", + table: "auth_sessions", + column: "challenge_id"); + + migrationBuilder.CreateIndex( + name: "ix_files_account_id", + table: "files", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_files_post_id", + table: "files", + column: "post_id"); + + migrationBuilder.CreateIndex( + name: "ix_magic_spells_account_id", + table: "magic_spells", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_magic_spells_spell", + table: "magic_spells", + column: "spell", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_notification_push_subscriptions_account_id", + table: "notification_push_subscriptions", + column: "account_id"); + + 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); + + migrationBuilder.CreateIndex( + name: "ix_notifications_account_id", + table: "notifications", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_permission_nodes_group_id", + table: "permission_nodes", + column: "group_id"); + + migrationBuilder.CreateIndex( + name: "ix_permission_nodes_key_area_actor", + table: "permission_nodes", + columns: new[] { "key", "area", "actor" }); + + migrationBuilder.CreateIndex( + name: "ix_post_category_links_posts_id", + table: "post_category_links", + column: "posts_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_collection_links_posts_id", + table: "post_collection_links", + column: "posts_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_collections_publisher_id", + table: "post_collections", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_reactions_account_id", + table: "post_reactions", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_reactions_post_id", + table: "post_reactions", + column: "post_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_tag_links_tags_id", + table: "post_tag_links", + column: "tags_id"); + + migrationBuilder.CreateIndex( + name: "ix_posts_forwarded_post_id", + table: "posts", + column: "forwarded_post_id"); + + migrationBuilder.CreateIndex( + name: "ix_posts_publisher_id", + table: "posts", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_posts_replied_post_id", + table: "posts", + column: "replied_post_id"); + + migrationBuilder.CreateIndex( + name: "ix_posts_threaded_post_id", + table: "posts", + column: "threaded_post_id", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_publisher_members_account_id", + table: "publisher_members", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_publishers_account_id", + table: "publishers", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_publishers_background_id", + table: "publishers", + column: "background_id"); + + migrationBuilder.CreateIndex( + name: "ix_publishers_name", + table: "publishers", + column: "name", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_publishers_picture_id", + table: "publishers", + 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_files_posts_post_id", + table: "files", + column: "post_id", + principalTable: "posts", + principalColumn: "id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_files_accounts_account_id", + table: "files"); + + migrationBuilder.DropForeignKey( + name: "fk_publishers_accounts_account_id", + table: "publishers"); + + migrationBuilder.DropForeignKey( + name: "fk_publishers_files_background_id", + table: "publishers"); + + migrationBuilder.DropForeignKey( + name: "fk_publishers_files_picture_id", + table: "publishers"); + + migrationBuilder.DropTable( + name: "account_auth_factors"); + + migrationBuilder.DropTable( + name: "account_contacts"); + + migrationBuilder.DropTable( + name: "account_profiles"); + + migrationBuilder.DropTable( + name: "account_relationships"); + + migrationBuilder.DropTable( + name: "auth_sessions"); + + migrationBuilder.DropTable( + name: "magic_spells"); + + migrationBuilder.DropTable( + name: "notification_push_subscriptions"); + + migrationBuilder.DropTable( + name: "notifications"); + + migrationBuilder.DropTable( + name: "permission_group_members"); + + migrationBuilder.DropTable( + name: "permission_nodes"); + + migrationBuilder.DropTable( + name: "post_category_links"); + + migrationBuilder.DropTable( + name: "post_collection_links"); + + migrationBuilder.DropTable( + name: "post_reactions"); + + migrationBuilder.DropTable( + name: "post_tag_links"); + + migrationBuilder.DropTable( + name: "publisher_members"); + + migrationBuilder.DropTable( + name: "auth_challenges"); + + migrationBuilder.DropTable( + name: "permission_groups"); + + migrationBuilder.DropTable( + name: "post_categories"); + + migrationBuilder.DropTable( + name: "post_collections"); + + migrationBuilder.DropTable( + name: "post_tags"); + + migrationBuilder.DropTable( + name: "accounts"); + + migrationBuilder.DropTable( + name: "files"); + + migrationBuilder.DropTable( + name: "posts"); + + migrationBuilder.DropTable( + name: "publishers"); + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs index 383a46a..5c6962b 100644 --- a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs +++ b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs @@ -1,6 +1,7 @@ // using System; using System.Collections.Generic; +using System.Text.Json; using DysonNetwork.Sphere; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -33,6 +34,10 @@ namespace DysonNetwork.Sphere.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("ActivatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("activated_at"); + b.Property("CreatedAt") .HasColumnType("timestamp with time zone") .HasColumnName("created_at"); @@ -167,6 +172,65 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("account_contacts", (string)null); }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("bigint") + .HasColumnName("account_id"); + + b.Property("AffectedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("affected_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires_at"); + + b.Property>("Meta") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("Spell") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("spell"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_magic_spells"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_magic_spells_account_id"); + + b.HasIndex("Spell") + .IsUnique() + .HasDatabaseName("ix_magic_spells_spell"); + + b.ToTable("magic_spells", (string)null); + }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => { b.Property("Id") @@ -427,6 +491,10 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("expired_at"); + b.Property("FailedAttempts") + .HasColumnType("integer") + .HasColumnName("failed_attempts"); + b.Property("IpAddress") .HasMaxLength(128) .HasColumnType("character varying(128)") @@ -552,9 +620,10 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("group_id"); - b.Property("AccountId") - .HasColumnType("bigint") - .HasColumnName("account_id"); + b.Property("Actor") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("actor"); b.Property("AffectedAt") .HasColumnType("timestamp with time zone") @@ -576,13 +645,10 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("updated_at"); - b.HasKey("GroupId", "AccountId") - .HasName("pk_permission_group_member"); + b.HasKey("GroupId", "Actor") + .HasName("pk_permission_group_members"); - b.HasIndex("AccountId") - .HasDatabaseName("ix_permission_group_member_account_id"); - - b.ToTable("permission_group_member", (string)null); + b.ToTable("permission_group_members", (string)null); }); modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b => @@ -630,15 +696,11 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(1024)") .HasColumnName("key"); - b.Property("PermissionGroupId") - .HasColumnType("uuid") - .HasColumnName("permission_group_id"); - b.Property("UpdatedAt") .HasColumnType("timestamp with time zone") .HasColumnName("updated_at"); - b.Property("Value") + b.Property("Value") .IsRequired() .HasColumnType("jsonb") .HasColumnName("value"); @@ -649,9 +711,6 @@ namespace DysonNetwork.Sphere.Migrations b.HasIndex("GroupId") .HasDatabaseName("ix_permission_nodes_group_id"); - b.HasIndex("PermissionGroupId") - .HasDatabaseName("ix_permission_nodes_permission_group_id"); - b.HasIndex("Key", "Area", "Actor") .HasDatabaseName("ix_permission_nodes_key_area_actor"); @@ -1228,6 +1287,16 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Account"); }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .HasConstraintName("fk_magic_spells_accounts_account_id"); + + b.Navigation("Account"); + }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => { b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") @@ -1334,36 +1403,22 @@ namespace DysonNetwork.Sphere.Migrations modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroupMember", b => { - b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") - .WithMany("GroupMemberships") - .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_permission_group_member_accounts_account_id"); - b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group") .WithMany("Members") .HasForeignKey("GroupId") .OnDelete(DeleteBehavior.Cascade) .IsRequired() - .HasConstraintName("fk_permission_group_member_permission_groups_group_id"); - - b.Navigation("Account"); + .HasConstraintName("fk_permission_group_members_permission_groups_group_id"); b.Navigation("Group"); }); modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b => { - b.HasOne("DysonNetwork.Sphere.Permission.PermissionNode", "Group") - .WithMany() - .HasForeignKey("GroupId") - .HasConstraintName("fk_permission_nodes_permission_nodes_group_id"); - - b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", null) + b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group") .WithMany("Nodes") - .HasForeignKey("PermissionGroupId") - .HasConstraintName("fk_permission_nodes_permission_groups_permission_group_id"); + .HasForeignKey("GroupId") + .HasConstraintName("fk_permission_nodes_permission_groups_group_id"); b.Navigation("Group"); }); @@ -1557,8 +1612,6 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Contacts"); - b.Navigation("GroupMemberships"); - b.Navigation("IncomingRelationships"); b.Navigation("OutgoingRelationships"); diff --git a/DysonNetwork.Sphere/Pages/CheckpointPage.cshtml b/DysonNetwork.Sphere/Pages/CheckpointPage.cshtml index 2fcf464..de1a2f1 100644 --- a/DysonNetwork.Sphere/Pages/CheckpointPage.cshtml +++ b/DysonNetwork.Sphere/Pages/CheckpointPage.cshtml @@ -125,8 +125,7 @@
Hosted by DysonNetwork.Sphere diff --git a/DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml b/DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml new file mode 100644 index 0000000..f86b5dd --- /dev/null +++ b/DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml @@ -0,0 +1,98 @@ +@page "/spells/{spellWord}" +@using DysonNetwork.Sphere.Account +@model DysonNetwork.Sphere.Pages.MagicSpellPage + +@{ + Layout = null; + + var spell = ViewData["Spell"] as MagicSpell; +} + + + + + + + + + Solar Network Magic Spell + + + + +
+
+

Magic Spell

+ @if (spell == null) + { +
+

The spell was expired or not exists.

+
+ } + else + { +
+

The spell was applied successfully!

+
+ } +
+ +
+ + \ No newline at end of file diff --git a/DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml.cs b/DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml.cs new file mode 100644 index 0000000..10ae3b9 --- /dev/null +++ b/DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml.cs @@ -0,0 +1,24 @@ +using DysonNetwork.Sphere.Account; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.EntityFrameworkCore; +using NodaTime; + +namespace DysonNetwork.Sphere.Pages; + +public class MagicSpellPage(AppDatabase db, MagicSpellService spells) : PageModel +{ + public async Task OnGet(string spellWord) + { + var now = SystemClock.Instance.GetCurrentInstant(); + var spell = await db.MagicSpells + .Where(e => e.Spell == spellWord) + .Where(e => e.ExpiresAt == null || now >= e.ExpiresAt) + .Where(e => e.AffectedAt == null || now >= e.AffectedAt) + .FirstOrDefaultAsync(); + + ViewData["Spell"] = spell; + + return Page(); + } +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Permission/Permission.cs b/DysonNetwork.Sphere/Permission/Permission.cs index 65562c7..cc0aa94 100644 --- a/DysonNetwork.Sphere/Permission/Permission.cs +++ b/DysonNetwork.Sphere/Permission/Permission.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using NodaTime; @@ -18,18 +19,24 @@ namespace DysonNetwork.Sphere.Permission; /// and when the permission node has a GroupId, the actor will be set to the group, but it won't work on checking /// expect the member of that permission group inherent the permission from the group. [Index(nameof(Key), nameof(Area), nameof(Actor))] -public class PermissionNode : ModelBase +public class PermissionNode : ModelBase, IDisposable { public Guid Id { get; set; } = Guid.NewGuid(); [MaxLength(1024)] public string Actor { get; set; } = null!; [MaxLength(1024)] public string Area { get; set; } = null!; [MaxLength(1024)] public string Key { get; set; } = null!; - [Column(TypeName = "jsonb")] public object Value { get; set; } = null!; + [Column(TypeName = "jsonb")] public JsonDocument Value { get; set; } = null!; public Instant? ExpiredAt { get; set; } = null; public Instant? AffectedAt { get; set; } = null; - + public Guid? GroupId { get; set; } = null; - [JsonIgnore] public PermissionNode? Group { get; set; } = null; + [JsonIgnore] public PermissionGroup? Group { get; set; } = null; + + public void Dispose() + { + Value.Dispose(); + GC.SuppressFinalize(this); + } } public class PermissionGroup : ModelBase @@ -44,10 +51,9 @@ public class PermissionGroup : ModelBase public class PermissionGroupMember : ModelBase { public Guid GroupId { get; set; } - public long AccountId { get; set; } public PermissionGroup Group { get; set; } = null!; - public Account.Account Account { get; set; } = null!; - - public Instant? ExpiredAt { get; set; } = null; - public Instant? AffectedAt { get; set; } = null; + [MaxLength(1024)] public string Actor { get; set; } = null!; + + public Instant? ExpiredAt { get; set; } + public Instant? AffectedAt { get; set; } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Permission/PermissionMiddleware.cs b/DysonNetwork.Sphere/Permission/PermissionMiddleware.cs new file mode 100644 index 0000000..a6a6934 --- /dev/null +++ b/DysonNetwork.Sphere/Permission/PermissionMiddleware.cs @@ -0,0 +1,51 @@ +namespace DysonNetwork.Sphere.Permission; + +using System; + +[AttributeUsage(AttributeTargets.Method, Inherited = true)] +public class RequiredPermissionAttribute(string area, string key) : Attribute +{ + public string Area { get; set; } = area; + public string Key { get; } = key; +} + +public class PermissionMiddleware(RequestDelegate next) +{ + public async Task InvokeAsync(HttpContext httpContext, PermissionService pm) + { + var endpoint = httpContext.GetEndpoint(); + + var attr = endpoint?.Metadata + .OfType() + .FirstOrDefault(); + + if (attr != null) + { + if (httpContext.Items["CurrentUser"] is not Account.Account currentUser) + { + httpContext.Response.StatusCode = StatusCodes.Status403Forbidden; + await httpContext.Response.WriteAsync("Unauthorized"); + return; + } + + if (currentUser.IsSuperuser) + { + // Bypass the permission check for performance + await next(httpContext); + return; + } + + var actor = $"user:{currentUser.Id}"; + var permNode = await pm.GetPermissionAsync(actor, attr.Area, attr.Key); + + if (!permNode) + { + httpContext.Response.StatusCode = StatusCodes.Status403Forbidden; + await httpContext.Response.WriteAsync($"Permission {attr.Area}/{attr.Key} = {true} was required."); + return; + } + } + + await next(httpContext); + } +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Permission/PermissionService.cs b/DysonNetwork.Sphere/Permission/PermissionService.cs new file mode 100644 index 0000000..74edaec --- /dev/null +++ b/DysonNetwork.Sphere/Permission/PermissionService.cs @@ -0,0 +1,126 @@ +using System.Text.Json; +using Microsoft.EntityFrameworkCore; +using NodaTime; + +namespace DysonNetwork.Sphere.Permission; + +public class PermissionService(AppDatabase db) +{ + public async Task GetPermissionAsync(string actor, string area, string key) + { + var now = SystemClock.Instance.GetCurrentInstant(); + var groupsId = await db.PermissionGroupMembers + .Where(n => n.Actor == actor) + .Where(n => n.ExpiredAt == null || n.ExpiredAt < now) + .Where(n => n.AffectedAt == null || n.AffectedAt >= now) + .Select(e => e.GroupId) + .ToListAsync(); + var permission = await db.PermissionNodes + .Where(n => n.GroupId == null || groupsId.Contains(n.GroupId.Value)) + .Where(n => n.Key == key && n.Actor == actor && n.Area == area) + .Where(n => n.ExpiredAt == null || n.ExpiredAt < now) + .Where(n => n.AffectedAt == null || n.AffectedAt >= now) + .FirstOrDefaultAsync(); + + return permission is not null ? _DeserializePermissionValue(permission.Value) : default; + } + + public async Task AddPermissionNode( + string actor, + string area, + string key, + T value, + Instant? expiredAt = null, + Instant? affectedAt = null + ) + { + if (value is null) throw new ArgumentNullException(nameof(value)); + + var node = new PermissionNode + { + Actor = actor, + Key = key, + Area = area, + Value = _SerializePermissionValue(value), + ExpiredAt = expiredAt, + AffectedAt = affectedAt + }; + + db.PermissionNodes.Add(node); + await db.SaveChangesAsync(); + + return node; + } + + public async Task AddPermissionNodeToGroup( + PermissionGroup group, + string actor, + string area, + string key, + T value, + Instant? expiredAt = null, + Instant? affectedAt = null + ) + { + if (value is null) throw new ArgumentNullException(nameof(value)); + + var node = new PermissionNode + { + Actor = actor, + Key = key, + Area = area, + Value = _SerializePermissionValue(value), + ExpiredAt = expiredAt, + AffectedAt = affectedAt, + Group = group, + GroupId = group.Id + }; + + db.PermissionNodes.Add(node); + await db.SaveChangesAsync(); + + return node; + } + + public async Task RemovePermissionNode(string actor, string area, string key) + { + var node = await db.PermissionNodes + .Where(n => n.Actor == actor && n.Area == area && n.Key == key) + .FirstOrDefaultAsync(); + if (node is not null) db.PermissionNodes.Remove(node); + await db.SaveChangesAsync(); + } + + public async Task RemovePermissionNodeFromGroup(PermissionGroup group, string actor, string area, string key) + { + var node = await db.PermissionNodes + .Where(n => n.GroupId == group.Id) + .Where(n => n.Actor == actor && n.Area == area && n.Key == key) + .FirstOrDefaultAsync(); + if (node is null) return; + db.PermissionNodes.Remove(node); + await db.SaveChangesAsync(); + } + + private static T? _DeserializePermissionValue(JsonDocument json) + { + return JsonSerializer.Deserialize(json.RootElement.GetRawText()); + } + + private static JsonDocument _SerializePermissionValue(T obj) + { + var str = JsonSerializer.Serialize(obj); + return JsonDocument.Parse(str); + } + + public static PermissionNode NewPermissionNode(string actor, string area, string key, T value) + { + return new PermissionNode + { + Actor = actor, + Area = area, + Key = key, + Value = _SerializePermissionValue(value), + }; + } +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Post/PostController.cs b/DysonNetwork.Sphere/Post/PostController.cs index bf9b8f7..31e95e8 100644 --- a/DysonNetwork.Sphere/Post/PostController.cs +++ b/DysonNetwork.Sphere/Post/PostController.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using Casbin; +using DysonNetwork.Sphere.Permission; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using NodaTime; @@ -8,7 +9,7 @@ namespace DysonNetwork.Sphere.Post; [ApiController] [Route("/posts")] -public class PostController(AppDatabase db, PostService ps, IEnforcer enforcer) : ControllerBase +public class PostController(AppDatabase db, PostService ps) : ControllerBase { [HttpGet] public async Task>> ListPosts([FromQuery] int offset = 0, [FromQuery] int take = 20) @@ -118,14 +119,13 @@ public class PostController(AppDatabase db, PostService ps, IEnforcer enforcer) } [HttpPost] + [RequiredPermission("global", "posts.create")] public async Task> CreatePost( [FromBody] PostRequest request, [FromHeader(Name = "X-Pub")] string? publisherName ) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); - if (!await enforcer.EnforceAsync((string)HttpContext.Items["CurrentIdentity"]!, "global", "posts", "create")) - return StatusCode(403); Publisher? publisher; if (publisherName is null) diff --git a/DysonNetwork.Sphere/Post/PublisherController.cs b/DysonNetwork.Sphere/Post/PublisherController.cs index 567c27a..e5e8a45 100644 --- a/DysonNetwork.Sphere/Post/PublisherController.cs +++ b/DysonNetwork.Sphere/Post/PublisherController.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using Casbin; +using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Storage; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -10,7 +11,7 @@ namespace DysonNetwork.Sphere.Post; [ApiController] [Route("/publishers")] -public class PublisherController(AppDatabase db, PublisherService ps, FileService fs, IEnforcer enforcer) +public class PublisherController(AppDatabase db, PublisherService ps, FileService fs) : ControllerBase { [HttpGet("{name}")] @@ -167,12 +168,10 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic [HttpPost("individual")] [Authorize] + [RequiredPermission("global", "publishers.create")] public async Task> CreatePublisherIndividual(PublisherRequest request) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); - if (!await enforcer.EnforceAsync((string)HttpContext.Items["CurrentIdentity"]!, "global", "publishers", - "create")) - return StatusCode(403); var takenName = request.Name ?? currentUser.Name; var duplicateNameCount = await db.Publishers diff --git a/DysonNetwork.Sphere/Program.cs b/DysonNetwork.Sphere/Program.cs index 51c1a82..5674032 100644 --- a/DysonNetwork.Sphere/Program.cs +++ b/DysonNetwork.Sphere/Program.cs @@ -8,6 +8,7 @@ using Casbin.Persist.Adapter.EFCore; using DysonNetwork.Sphere; using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Auth; +using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Post; using DysonNetwork.Sphere.Storage; using Microsoft.AspNetCore.Authorization; @@ -45,22 +46,6 @@ builder.Services.AddControllers().AddJsonOptions(options => }); builder.Services.AddRazorPages(); -// Casbin permissions - -var casbinDbContext = new CasbinDbContext( - new DbContextOptionsBuilder>() - .UseNpgsql(builder.Configuration.GetConnectionString("Guard")) - .Options -); -var casbinEfcore = new EFCoreAdapter(casbinDbContext); -casbinDbContext.Database.EnsureCreated(); -var casbinEncofcer = new Enforcer("Casbin.conf", casbinEfcore); -casbinEncofcer.EnableCache(true); -casbinEncofcer.LoadPolicy(); - -builder.Services.AddSingleton(casbinEncofcer); -builder.Services.AddSingleton(); - // Other pipelines builder.Services.AddRateLimiter(o => o.AddFixedWindowLimiter(policyName: "fixed", opts => @@ -129,7 +114,10 @@ builder.Services.AddSwaggerGen(options => }); builder.Services.AddOpenApi(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -163,7 +151,7 @@ var app = builder.Build(); using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); - db.Database.Migrate(); + await db.Database.MigrateAsync(); } app.MapOpenApi(); @@ -189,6 +177,7 @@ app.UseRateLimiter(); app.UseHttpsRedirection(); app.UseAuthorization(); app.UseMiddleware(); +app.UseMiddleware(); app.MapControllers().RequireRateLimiting("fixed"); app.MapStaticAssets().RequireRateLimiting("fixed"); diff --git a/DysonNetwork.Sphere/appsettings.json b/DysonNetwork.Sphere/appsettings.json index c3c393c..dedc37b 100644 --- a/DysonNetwork.Sphere/appsettings.json +++ b/DysonNetwork.Sphere/appsettings.json @@ -7,8 +7,7 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "App": "Host=localhost;Port=5432;Database=dyson_network;Username=postgres;Password=postgres", - "Guard": "Host=localhost;Port=5432;Database=dyson_network_casbin;Username=postgres;Password=postgres" + "App": "Host=localhost;Port=5432;Database=dyson_network;Username=postgres;Password=postgres" }, "Authentication": { "Schemes": { @@ -55,11 +54,20 @@ "Production": true, "Google": "path/to/config.json", "Apple": { - "PrivateKey": "path/to/cert.p8", + "PrivateKey": "path/to/cert.p8", "PrivateKeyId": "", "TeamId": "", "BundleIdentifier": "" } } + }, + "Email": { + "Server": "", + "Port": 465, + "Username": "", + "Password": "", + "FromAddress": "", + "FromName": "", + "SubjectPrefix": "Solar Network" } } diff --git a/DysonNetwork.sln.DotSettings.user b/DysonNetwork.sln.DotSettings.user index 83d68ee..cd7f0b2 100644 --- a/DysonNetwork.sln.DotSettings.user +++ b/DysonNetwork.sln.DotSettings.user @@ -2,6 +2,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -28,6 +29,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded