✨ Magic spell for one time code
🗑️ Drop the usage of casbin ♻️ Refactor the permission service ♻️ Refactor the flow of creating an account 🧱 Email infra structure
This commit is contained in:
parent
82288fa52c
commit
0ebeab672b
@ -13,6 +13,7 @@ public class Account : ModelBase
|
|||||||
[MaxLength(256)] public string Name { get; set; } = string.Empty;
|
[MaxLength(256)] public string Name { get; set; } = string.Empty;
|
||||||
[MaxLength(256)] public string Nick { get; set; } = string.Empty;
|
[MaxLength(256)] public string Nick { get; set; } = string.Empty;
|
||||||
[MaxLength(32)] public string Language { 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 bool IsSuperuser { get; set; } = false;
|
||||||
|
|
||||||
public Profile Profile { get; set; } = null!;
|
public Profile Profile { get; set; } = null!;
|
||||||
@ -24,8 +25,6 @@ public class Account : ModelBase
|
|||||||
|
|
||||||
[JsonIgnore] public ICollection<Relationship> OutgoingRelationships { get; set; } = new List<Relationship>();
|
[JsonIgnore] public ICollection<Relationship> OutgoingRelationships { get; set; } = new List<Relationship>();
|
||||||
[JsonIgnore] public ICollection<Relationship> IncomingRelationships { get; set; } = new List<Relationship>();
|
[JsonIgnore] public ICollection<Relationship> IncomingRelationships { get; set; } = new List<Relationship>();
|
||||||
|
|
||||||
[JsonIgnore] public ICollection<PermissionGroupMember> GroupMemberships { get; set; } = new List<PermissionGroupMember>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Profile : ModelBase
|
public class Profile : ModelBase
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using DysonNetwork.Sphere.Auth;
|
||||||
using DysonNetwork.Sphere.Storage;
|
using DysonNetwork.Sphere.Storage;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using NodaTime;
|
||||||
|
|
||||||
namespace DysonNetwork.Sphere.Account;
|
namespace DysonNetwork.Sphere.Account;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/accounts")]
|
[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}")]
|
[HttpGet("{name}")]
|
||||||
[ProducesResponseType<Account>(StatusCodes.Status200OK)]
|
[ProducesResponseType<Account>(StatusCodes.Status200OK)]
|
||||||
@ -39,6 +47,10 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
|||||||
[MinLength(4)]
|
[MinLength(4)]
|
||||||
[MaxLength(128)]
|
[MaxLength(128)]
|
||||||
public string Password { get; set; } = string.Empty;
|
public string Password { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[MaxLength(128)] public string Language { get; set; } = "en";
|
||||||
|
|
||||||
|
[Required] public string CaptchaToken { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -46,6 +58,8 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
|||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
public async Task<ActionResult<Account>> CreateAccount([FromBody] AccountCreateRequest request)
|
public async Task<ActionResult<Account>> 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();
|
var dupeNameCount = await db.Accounts.Where(a => a.Name == request.Name).CountAsync();
|
||||||
if (dupeNameCount > 0)
|
if (dupeNameCount > 0)
|
||||||
return BadRequest("The name is already taken.");
|
return BadRequest("The name is already taken.");
|
||||||
@ -54,6 +68,7 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
|||||||
{
|
{
|
||||||
Name = request.Name,
|
Name = request.Name,
|
||||||
Nick = request.Nick,
|
Nick = request.Nick,
|
||||||
|
Language = request.Language,
|
||||||
Contacts = new List<AccountContact>
|
Contacts = new List<AccountContact>
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
@ -75,6 +90,18 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
|||||||
|
|
||||||
await db.Accounts.AddAsync(account);
|
await db.Accounts.AddAsync(account);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
var spell = await spells.CreateMagicSpell(
|
||||||
|
account,
|
||||||
|
MagicSpellType.AccountActivation,
|
||||||
|
new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "contact_method", account.Contacts.First().Content }
|
||||||
|
},
|
||||||
|
expiredAt: SystemClock.Instance.GetCurrentInstant().Plus(Duration.FromDays(7))
|
||||||
|
);
|
||||||
|
spells.NotifyMagicSpell(spell);
|
||||||
|
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
using Casbin;
|
using Casbin;
|
||||||
|
using DysonNetwork.Sphere.Permission;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
|
|
||||||
namespace DysonNetwork.Sphere.Account;
|
namespace DysonNetwork.Sphere.Account;
|
||||||
|
|
||||||
public class AccountService(AppDatabase db, IEnforcer enforcer)
|
public class AccountService(AppDatabase db, PermissionService pm)
|
||||||
{
|
{
|
||||||
public async Task<Account?> LookupAccount(string probe)
|
public async Task<Account?> LookupAccount(string probe)
|
||||||
{
|
{
|
||||||
@ -145,18 +146,18 @@ public class AccountService(AppDatabase db, IEnforcer enforcer)
|
|||||||
// others: use the default permissions by design
|
// others: use the default permissions by design
|
||||||
|
|
||||||
var domain = $"user:{relationship.AccountId.ToString()}";
|
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.Friends => true,
|
||||||
RelationshipStatus.Blocked => "blocked",
|
RelationshipStatus.Blocked => false,
|
||||||
_ => "default" // fallback role
|
_ => null,
|
||||||
};
|
};
|
||||||
if (role == "default") return;
|
if (value is null) return;
|
||||||
|
|
||||||
await enforcer.AddRoleForUserAsync(target, role, domain);
|
await pm.AddPermissionNode(target, domain, "*", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
49
DysonNetwork.Sphere/Account/EmailService.cs
Normal file
49
DysonNetwork.Sphere/Account/EmailService.cs
Normal file
@ -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<EmailServiceConfiguration>("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);
|
||||||
|
}
|
||||||
|
}
|
30
DysonNetwork.Sphere/Account/MagicSpell.cs
Normal file
30
DysonNetwork.Sphere/Account/MagicSpell.cs
Normal file
@ -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<string, object> Meta { get; set; }
|
||||||
|
|
||||||
|
public long? AccountId { get; set; }
|
||||||
|
public Account? Account { get; set; }
|
||||||
|
}
|
122
DysonNetwork.Sphere/Account/MagicSpellService.cs
Normal file
122
DysonNetwork.Sphere/Account/MagicSpellService.cs
Normal file
@ -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<MagicSpellService> logger)
|
||||||
|
{
|
||||||
|
public async Task<MagicSpell> CreateMagicSpell(
|
||||||
|
Account account,
|
||||||
|
MagicSpellType type,
|
||||||
|
Dictionary<string, object> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using DysonNetwork.Sphere.Permission;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Design;
|
using Microsoft.EntityFrameworkCore.Design;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
@ -19,18 +20,24 @@ public class AppDatabase(
|
|||||||
IConfiguration configuration
|
IConfiguration configuration
|
||||||
) : DbContext(options)
|
) : DbContext(options)
|
||||||
{
|
{
|
||||||
public DbSet<Permission.PermissionNode> PermissionNodes { get; set; } = null!;
|
public DbSet<PermissionNode> PermissionNodes { get; set; } = null!;
|
||||||
public DbSet<Permission.PermissionGroup> PermissionGroups { get; set; } = null!;
|
public DbSet<PermissionGroup> PermissionGroups { get; set; } = null!;
|
||||||
|
public DbSet<PermissionGroupMember> PermissionGroupMembers { get; set; } = null!;
|
||||||
|
|
||||||
|
public DbSet<Account.MagicSpell> MagicSpells { get; set; } = null!;
|
||||||
public DbSet<Account.Account> Accounts { get; set; }
|
public DbSet<Account.Account> Accounts { get; set; }
|
||||||
public DbSet<Account.Profile> AccountProfiles { get; set; }
|
public DbSet<Account.Profile> AccountProfiles { get; set; }
|
||||||
public DbSet<Account.AccountContact> AccountContacts { get; set; }
|
public DbSet<Account.AccountContact> AccountContacts { get; set; }
|
||||||
public DbSet<Account.AccountAuthFactor> AccountAuthFactors { get; set; }
|
public DbSet<Account.AccountAuthFactor> AccountAuthFactors { get; set; }
|
||||||
public DbSet<Account.Relationship> AccountRelationships { get; set; }
|
public DbSet<Account.Relationship> AccountRelationships { get; set; }
|
||||||
public DbSet<Auth.Session> AuthSessions { get; set; }
|
|
||||||
public DbSet<Auth.Challenge> AuthChallenges { get; set; }
|
|
||||||
public DbSet<Account.Notification> Notifications { get; set; }
|
public DbSet<Account.Notification> Notifications { get; set; }
|
||||||
public DbSet<Account.NotificationPushSubscription> NotificationPushSubscriptions { get; set; }
|
public DbSet<Account.NotificationPushSubscription> NotificationPushSubscriptions { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Auth.Session> AuthSessions { get; set; }
|
||||||
|
public DbSet<Auth.Challenge> AuthChallenges { get; set; }
|
||||||
|
|
||||||
public DbSet<Storage.CloudFile> Files { get; set; }
|
public DbSet<Storage.CloudFile> Files { get; set; }
|
||||||
|
|
||||||
public DbSet<Post.Publisher> Publishers { get; set; }
|
public DbSet<Post.Publisher> Publishers { get; set; }
|
||||||
public DbSet<Post.PublisherMember> PublisherMembers { get; set; }
|
public DbSet<Post.PublisherMember> PublisherMembers { get; set; }
|
||||||
public DbSet<Post.Post> Posts { get; set; }
|
public DbSet<Post.Post> Posts { get; set; }
|
||||||
@ -51,6 +58,25 @@ public class AppDatabase(
|
|||||||
opt => opt.UseNodaTime()
|
opt => opt.UseNodaTime()
|
||||||
).UseSnakeCaseNamingConvention();
|
).UseSnakeCaseNamingConvention();
|
||||||
|
|
||||||
|
optionsBuilder.UseAsyncSeeding(async (context, _, cancellationToken) =>
|
||||||
|
{
|
||||||
|
var defaultPermissionGroup = await context.Set<PermissionGroup>()
|
||||||
|
.FirstOrDefaultAsync(g => g.Key == "default", cancellationToken);
|
||||||
|
if (defaultPermissionGroup is null)
|
||||||
|
{
|
||||||
|
context.Set<PermissionGroup>().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);
|
base.OnConfiguring(optionsBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,18 +85,12 @@ public class AppDatabase(
|
|||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
modelBuilder.Entity<Permission.PermissionGroupMember>()
|
modelBuilder.Entity<Permission.PermissionGroupMember>()
|
||||||
.HasKey(pg => new { pg.GroupId, pg.AccountId })
|
.HasKey(pg => new { pg.GroupId, pg.Actor });
|
||||||
.HasName("permission_group_members");
|
|
||||||
modelBuilder.Entity<Permission.PermissionGroupMember>()
|
modelBuilder.Entity<Permission.PermissionGroupMember>()
|
||||||
.HasOne(pg => pg.Group)
|
.HasOne(pg => pg.Group)
|
||||||
.WithMany(g => g.Members)
|
.WithMany(g => g.Members)
|
||||||
.HasForeignKey(pg => pg.GroupId)
|
.HasForeignKey(pg => pg.GroupId)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
modelBuilder.Entity<Permission.PermissionGroupMember>()
|
|
||||||
.HasOne(pg => pg.Account)
|
|
||||||
.WithMany(a => a.GroupMemberships)
|
|
||||||
.HasForeignKey(pg => pg.AccountId)
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Account.Account>()
|
modelBuilder.Entity<Account.Account>()
|
||||||
.HasOne(a => a.Profile)
|
.HasOne(a => a.Profile)
|
||||||
@ -113,7 +133,7 @@ public class AppDatabase(
|
|||||||
modelBuilder.Entity<Post.Post>()
|
modelBuilder.Entity<Post.Post>()
|
||||||
.HasOne(p => p.ForwardedPost)
|
.HasOne(p => p.ForwardedPost)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey(p => p.ForwardedPostId)
|
.HasForeignKey(p => p.ForwardedPostId)
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
modelBuilder.Entity<Post.Post>()
|
modelBuilder.Entity<Post.Post>()
|
||||||
.HasMany(p => p.Tags)
|
.HasMany(p => p.Tags)
|
||||||
|
@ -15,8 +15,7 @@ public class AuthController(
|
|||||||
AppDatabase db,
|
AppDatabase db,
|
||||||
AccountService accounts,
|
AccountService accounts,
|
||||||
AuthService auth,
|
AuthService auth,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration
|
||||||
IHttpClientFactory httpClientFactory
|
|
||||||
) : ControllerBase
|
) : ControllerBase
|
||||||
{
|
{
|
||||||
public class ChallengeRequest
|
public class ChallengeRequest
|
||||||
@ -218,49 +217,7 @@ public class AuthController(
|
|||||||
[HttpPost("captcha")]
|
[HttpPost("captcha")]
|
||||||
public async Task<ActionResult> ValidateCaptcha([FromBody] string token)
|
public async Task<ActionResult> ValidateCaptcha([FromBody] string token)
|
||||||
{
|
{
|
||||||
var provider = configuration.GetSection("Captcha")["Provider"]?.ToLower();
|
var result = await auth.ValidateCaptcha(token);
|
||||||
var apiKey = configuration.GetSection("Captcha")["ApiKey"];
|
return result ? Ok() : BadRequest();
|
||||||
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<CloudflareVerificationResponse>(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<GoogleVerificationResponse>(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.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using System.Text.Json;
|
||||||
using Casbin;
|
using Casbin;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
@ -15,66 +16,41 @@ public class SignedTokenPair
|
|||||||
public Instant ExpiredAt { get; set; }
|
public Instant ExpiredAt { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AuthService(AppDatabase db, IConfiguration config, IEnforcer enforcer)
|
public class AuthService(IConfiguration config, IHttpClientFactory httpClientFactory)
|
||||||
{
|
{
|
||||||
public async Task<bool> AssignRoleToUserAsync(string user, string role, string domain = "global")
|
public async Task<bool> ValidateCaptcha(string token)
|
||||||
{
|
{
|
||||||
var added = await enforcer.AddGroupingPolicyAsync(user, role, domain);
|
var provider = config.GetSection("Captcha")["Provider"]?.ToLower();
|
||||||
if (added) await enforcer.SavePolicyAsync();
|
var apiSecret = config.GetSection("Captcha")["ApiSecret"];
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> AddPermissionToUserAsync(string user, string domain, string obj, string act)
|
var client = httpClientFactory.CreateClient();
|
||||||
{
|
|
||||||
var added = await enforcer.AddPolicyAsync(user, domain, obj, act);
|
|
||||||
if (added) await enforcer.SavePolicyAsync();
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> RemovePermissionFromUserAsync(string user, string domain, string obj, string act)
|
switch (provider)
|
||||||
{
|
|
||||||
var removed = await enforcer.RemovePolicyAsync(user, domain, obj, act);
|
|
||||||
if (removed) await enforcer.SavePolicyAsync();
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> CreateRoleAsync(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);
|
case "cloudflare":
|
||||||
if (added) anyAdded = true;
|
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<CloudflareVerificationResponse>(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<GoogleVerificationResponse>(json);
|
||||||
|
|
||||||
|
return capResult?.Success == true;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("The server misconfigured for the captcha.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anyAdded) await enforcer.SavePolicyAsync();
|
|
||||||
return anyAdded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> 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<bool> 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)
|
public SignedTokenPair CreateToken(Session session)
|
||||||
@ -100,7 +76,7 @@ public class AuthService(AppDatabase db, IConfiguration config, IEnforcer enforc
|
|||||||
);
|
);
|
||||||
|
|
||||||
session.Challenge.Scopes.ForEach(c => claims.Add(new Claim("scope", c)));
|
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(
|
var accessTokenClaims = new JwtSecurityToken(
|
||||||
issuer: "solar-network",
|
issuer: "solar-network",
|
||||||
audience: string.Join(',', session.Challenge.Audiences),
|
audience: string.Join(',', session.Challenge.Audiences),
|
||||||
|
@ -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<CasbinRequirement>
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,6 +21,7 @@ public class Challenge : ModelBase
|
|||||||
public Instant? ExpiredAt { get; set; }
|
public Instant? ExpiredAt { get; set; }
|
||||||
public int StepRemain { get; set; }
|
public int StepRemain { get; set; }
|
||||||
public int StepTotal { get; set; }
|
public int StepTotal { get; set; }
|
||||||
|
public int FailedAttempts { get; set; }
|
||||||
[Column(TypeName = "jsonb")] public List<long> BlacklistFactors { get; set; } = new();
|
[Column(TypeName = "jsonb")] public List<long> BlacklistFactors { get; set; } = new();
|
||||||
[Column(TypeName = "jsonb")] public List<string> Audiences { get; set; } = new();
|
[Column(TypeName = "jsonb")] public List<string> Audiences { get; set; } = new();
|
||||||
[Column(TypeName = "jsonb")] public List<string> Scopes { get; set; } = new();
|
[Column(TypeName = "jsonb")] public List<string> Scopes { get; set; } = new();
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
<PackageReference Include="CorePush" Version="4.3.0" />
|
<PackageReference Include="CorePush" Version="4.3.0" />
|
||||||
<PackageReference Include="EFCore.NamingConventions" Version="9.0.0" />
|
<PackageReference Include="EFCore.NamingConventions" Version="9.0.0" />
|
||||||
<PackageReference Include="FFMpegCore" Version="5.2.0" />
|
<PackageReference Include="FFMpegCore" Version="5.2.0" />
|
||||||
|
<PackageReference Include="MailKit" Version="4.11.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.3">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.3">
|
||||||
|
@ -1,541 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
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
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
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<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<bool>("IsSuperuser")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_superuser");
|
|
||||||
|
|
||||||
b.Property<string>("Language")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(32)
|
|
||||||
.HasColumnType("character varying(32)")
|
|
||||||
.HasColumnName("language");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("name");
|
|
||||||
|
|
||||||
b.Property<string>("Nick")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("nick");
|
|
||||||
|
|
||||||
b.Property<Instant>("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<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<string>("Secret")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("secret");
|
|
||||||
|
|
||||||
b.Property<int>("Type")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("type");
|
|
||||||
|
|
||||||
b.Property<Instant>("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<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<string>("Content")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(1024)
|
|
||||||
.HasColumnType("character varying(1024)")
|
|
||||||
.HasColumnName("content");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<int>("Type")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("type");
|
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("updated_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("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<long>("Id")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
b.Property<string>("BackgroundId")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("background_id");
|
|
||||||
|
|
||||||
b.Property<string>("Bio")
|
|
||||||
.HasMaxLength(4096)
|
|
||||||
.HasColumnType("character varying(4096)")
|
|
||||||
.HasColumnName("bio");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<string>("FirstName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("first_name");
|
|
||||||
|
|
||||||
b.Property<string>("LastName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("last_name");
|
|
||||||
|
|
||||||
b.Property<string>("MiddleName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("middle_name");
|
|
||||||
|
|
||||||
b.Property<string>("PictureId")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("picture_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("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<Guid>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<List<string>>("Audiences")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasColumnName("audiences");
|
|
||||||
|
|
||||||
b.Property<List<long>>("BlacklistFactors")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasColumnName("blacklist_factors");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<string>("DeviceId")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("device_id");
|
|
||||||
|
|
||||||
b.Property<Instant?>("ExpiredAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("expired_at");
|
|
||||||
|
|
||||||
b.Property<string>("IpAddress")
|
|
||||||
.HasMaxLength(128)
|
|
||||||
.HasColumnType("character varying(128)")
|
|
||||||
.HasColumnName("ip_address");
|
|
||||||
|
|
||||||
b.Property<string>("Nonce")
|
|
||||||
.HasMaxLength(1024)
|
|
||||||
.HasColumnType("character varying(1024)")
|
|
||||||
.HasColumnName("nonce");
|
|
||||||
|
|
||||||
b.Property<List<string>>("Scopes")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasColumnName("scopes");
|
|
||||||
|
|
||||||
b.Property<int>("StepRemain")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("step_remain");
|
|
||||||
|
|
||||||
b.Property<int>("StepTotal")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("step_total");
|
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("updated_at");
|
|
||||||
|
|
||||||
b.Property<string>("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<Guid>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<Guid>("ChallengeId")
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasColumnName("challenge_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("ExpiredAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("expired_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("LastGrantedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_granted_at");
|
|
||||||
|
|
||||||
b.Property<Instant>("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<string>("Id")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(4096)
|
|
||||||
.HasColumnType("character varying(4096)")
|
|
||||||
.HasColumnName("description");
|
|
||||||
|
|
||||||
b.Property<Dictionary<string, object>>("FileMeta")
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasColumnName("file_meta");
|
|
||||||
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("MimeType")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("mime_type");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(1024)
|
|
||||||
.HasColumnType("character varying(1024)")
|
|
||||||
.HasColumnName("name");
|
|
||||||
|
|
||||||
b.Property<long>("Size")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("size");
|
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("updated_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("UploadedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("uploaded_at");
|
|
||||||
|
|
||||||
b.Property<string>("UploadedTo")
|
|
||||||
.HasMaxLength(128)
|
|
||||||
.HasColumnType("character varying(128)")
|
|
||||||
.HasColumnName("uploaded_to");
|
|
||||||
|
|
||||||
b.Property<int>("UsedCount")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("used_count");
|
|
||||||
|
|
||||||
b.Property<Dictionary<string, object>>("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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class InitialMigration : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "accounts",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
|
||||||
nick = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
|
||||||
language = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
||||||
is_superuser = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_accounts", x => x.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "account_auth_factors",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
type = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
secret = table.Column<string>(type: "text", nullable: true),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
type = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
verified_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
content = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
|
||||||
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
step_remain = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
step_total = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
blacklist_factors = table.Column<List<long>>(type: "jsonb", nullable: false),
|
|
||||||
audiences = table.Column<List<string>>(type: "jsonb", nullable: false),
|
|
||||||
scopes = table.Column<List<string>>(type: "jsonb", nullable: false),
|
|
||||||
ip_address = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
|
||||||
user_agent = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
|
|
||||||
device_id = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
nonce = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<string>(type: "text", nullable: false),
|
|
||||||
name = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
|
||||||
description = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
|
||||||
file_meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: true),
|
|
||||||
user_meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: true),
|
|
||||||
mime_type = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
hash = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
size = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
uploaded_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
uploaded_to = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
|
||||||
used_count = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
|
||||||
last_granted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
challenge_id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false),
|
|
||||||
first_name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
middle_name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
last_name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
bio = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
|
||||||
picture_id = table.Column<string>(type: "text", nullable: true),
|
|
||||||
background_id = table.Column<string>(type: "text", nullable: true),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,605 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
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
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
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<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<bool>("IsSuperuser")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_superuser");
|
|
||||||
|
|
||||||
b.Property<string>("Language")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(32)
|
|
||||||
.HasColumnType("character varying(32)")
|
|
||||||
.HasColumnName("language");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("name");
|
|
||||||
|
|
||||||
b.Property<string>("Nick")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("nick");
|
|
||||||
|
|
||||||
b.Property<Instant>("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<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<string>("Secret")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("secret");
|
|
||||||
|
|
||||||
b.Property<int>("Type")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("type");
|
|
||||||
|
|
||||||
b.Property<Instant>("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<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<string>("Content")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(1024)
|
|
||||||
.HasColumnType("character varying(1024)")
|
|
||||||
.HasColumnName("content");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<int>("Type")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("type");
|
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("updated_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("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<long>("Id")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
b.Property<string>("BackgroundId")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("background_id");
|
|
||||||
|
|
||||||
b.Property<string>("Bio")
|
|
||||||
.HasMaxLength(4096)
|
|
||||||
.HasColumnType("character varying(4096)")
|
|
||||||
.HasColumnName("bio");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<string>("FirstName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("first_name");
|
|
||||||
|
|
||||||
b.Property<string>("LastName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("last_name");
|
|
||||||
|
|
||||||
b.Property<string>("MiddleName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("middle_name");
|
|
||||||
|
|
||||||
b.Property<string>("PictureId")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("picture_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("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<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<long>("RelatedId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("related_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("ExpiredAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("expired_at");
|
|
||||||
|
|
||||||
b.Property<int>("Status")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("status");
|
|
||||||
|
|
||||||
b.Property<Instant>("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<Guid>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<List<string>>("Audiences")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasColumnName("audiences");
|
|
||||||
|
|
||||||
b.Property<List<long>>("BlacklistFactors")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasColumnName("blacklist_factors");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<string>("DeviceId")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("device_id");
|
|
||||||
|
|
||||||
b.Property<Instant?>("ExpiredAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("expired_at");
|
|
||||||
|
|
||||||
b.Property<string>("IpAddress")
|
|
||||||
.HasMaxLength(128)
|
|
||||||
.HasColumnType("character varying(128)")
|
|
||||||
.HasColumnName("ip_address");
|
|
||||||
|
|
||||||
b.Property<string>("Nonce")
|
|
||||||
.HasMaxLength(1024)
|
|
||||||
.HasColumnType("character varying(1024)")
|
|
||||||
.HasColumnName("nonce");
|
|
||||||
|
|
||||||
b.Property<List<string>>("Scopes")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasColumnName("scopes");
|
|
||||||
|
|
||||||
b.Property<int>("StepRemain")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("step_remain");
|
|
||||||
|
|
||||||
b.Property<int>("StepTotal")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("step_total");
|
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("updated_at");
|
|
||||||
|
|
||||||
b.Property<string>("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<Guid>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<Guid>("ChallengeId")
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasColumnName("challenge_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("ExpiredAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("expired_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("LastGrantedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_granted_at");
|
|
||||||
|
|
||||||
b.Property<Instant>("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<string>("Id")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("account_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("created_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("DeletedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("deleted_at");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(4096)
|
|
||||||
.HasColumnType("character varying(4096)")
|
|
||||||
.HasColumnName("description");
|
|
||||||
|
|
||||||
b.Property<Dictionary<string, object>>("FileMeta")
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasColumnName("file_meta");
|
|
||||||
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("MimeType")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)")
|
|
||||||
.HasColumnName("mime_type");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(1024)
|
|
||||||
.HasColumnType("character varying(1024)")
|
|
||||||
.HasColumnName("name");
|
|
||||||
|
|
||||||
b.Property<long>("Size")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("size");
|
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("updated_at");
|
|
||||||
|
|
||||||
b.Property<Instant?>("UploadedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("uploaded_at");
|
|
||||||
|
|
||||||
b.Property<string>("UploadedTo")
|
|
||||||
.HasMaxLength(128)
|
|
||||||
.HasColumnType("character varying(128)")
|
|
||||||
.HasColumnName("uploaded_to");
|
|
||||||
|
|
||||||
b.Property<int>("UsedCount")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("used_count");
|
|
||||||
|
|
||||||
b.Property<Dictionary<string, object>>("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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using NodaTime;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace DysonNetwork.Sphere.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class AddRelationship : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "account_relationships",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
related_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
status = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "account_relationships");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -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
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class AddPost : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<long>(
|
|
||||||
name: "post_id",
|
|
||||||
table: "files",
|
|
||||||
type: "bigint",
|
|
||||||
nullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "post_categories",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
slug = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
|
||||||
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_post_categories", x => x.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "post_tags",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
slug = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
|
||||||
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_post_tags", x => x.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "publishers",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
publisher_type = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
|
||||||
nick = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
|
||||||
bio = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
|
||||||
picture_id = table.Column<string>(type: "text", nullable: true),
|
|
||||||
background_id = table.Column<string>(type: "text", nullable: true),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: true),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
slug = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
|
||||||
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
description = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
|
||||||
publisher_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
title = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
|
|
||||||
description = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
|
||||||
language = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
|
||||||
edited_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
published_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
visibility = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
content = table.Column<string>(type: "text", nullable: true),
|
|
||||||
type = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: true),
|
|
||||||
views_unique = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
views_total = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
upvotes = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
downvotes = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
threaded_post_id = table.Column<long>(type: "bigint", nullable: true),
|
|
||||||
replied_post_id = table.Column<long>(type: "bigint", nullable: true),
|
|
||||||
forwarded_post_id = table.Column<long>(type: "bigint", nullable: true),
|
|
||||||
publisher_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
role = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
joined_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false),
|
|
||||||
posts_id = table.Column<long>(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<long>(type: "bigint", nullable: false),
|
|
||||||
posts_id = table.Column<long>(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<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
symbol = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
|
||||||
attitude = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
post_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false),
|
|
||||||
tags_id = table.Column<long>(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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,201 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using NodaTime;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace DysonNetwork.Sphere.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class AddNotification : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "picture_id",
|
|
||||||
table: "publishers",
|
|
||||||
type: "character varying(128)",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "background_id",
|
|
||||||
table: "publishers",
|
|
||||||
type: "character varying(128)",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "id",
|
|
||||||
table: "files",
|
|
||||||
type: "character varying(128)",
|
|
||||||
maxLength: 128,
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text");
|
|
||||||
|
|
||||||
migrationBuilder.AddColumn<Instant>(
|
|
||||||
name: "expired_at",
|
|
||||||
table: "files",
|
|
||||||
type: "timestamp with time zone",
|
|
||||||
nullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "picture_id",
|
|
||||||
table: "account_profiles",
|
|
||||||
type: "character varying(128)",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
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<Guid>(type: "uuid", nullable: false),
|
|
||||||
device_id = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
|
||||||
device_token = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
|
||||||
provider = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
last_used_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
|
||||||
title = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
|
|
||||||
subtitle = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
|
||||||
content = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
|
||||||
meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: true),
|
|
||||||
priority = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
viewed_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
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<string>(
|
|
||||||
name: "picture_id",
|
|
||||||
table: "publishers",
|
|
||||||
type: "text",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(128)",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "background_id",
|
|
||||||
table: "publishers",
|
|
||||||
type: "text",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(128)",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "id",
|
|
||||||
table: "files",
|
|
||||||
type: "text",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(128)",
|
|
||||||
oldMaxLength: 128);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "picture_id",
|
|
||||||
table: "account_profiles",
|
|
||||||
type: "text",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(128)",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "background_id",
|
|
||||||
table: "account_profiles",
|
|
||||||
type: "text",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(128)",
|
|
||||||
oldNullable: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,137 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using NodaTime;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace DysonNetwork.Sphere.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class AddPermission : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<string>(
|
|
||||||
name: "topic",
|
|
||||||
table: "notifications",
|
|
||||||
type: "character varying(1024)",
|
|
||||||
maxLength: 1024,
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: "");
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "permission_groups",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
||||||
key = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_permission_groups", x => x.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "permission_group_member",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
group_id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
||||||
account_id = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
affected_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
|
||||||
actor = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
|
||||||
area = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
|
||||||
key = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
|
||||||
value = table.Column<object>(type: "jsonb", nullable: false),
|
|
||||||
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
affected_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
|
||||||
group_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
||||||
permission_group_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json;
|
||||||
using DysonNetwork.Sphere;
|
using DysonNetwork.Sphere;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
@ -14,8 +15,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace DysonNetwork.Sphere.Migrations
|
namespace DysonNetwork.Sphere.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(AppDatabase))]
|
[DbContext(typeof(AppDatabase))]
|
||||||
[Migration("20250427161252_AddPermission")]
|
[Migration("20250429115700_InitialMigration")]
|
||||||
partial class AddPermission
|
partial class InitialMigration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
@ -36,6 +37,10 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<Instant?>("ActivatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("activated_at");
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
b.Property<Instant>("CreatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("created_at");
|
.HasColumnName("created_at");
|
||||||
@ -170,6 +175,65 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
b.ToTable("account_contacts", (string)null);
|
b.ToTable("account_contacts", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<long?>("AccountId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("account_id");
|
||||||
|
|
||||||
|
b.Property<Instant?>("AffectedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("affected_at");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("ExpiresAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("expires_at");
|
||||||
|
|
||||||
|
b.Property<Dictionary<string, object>>("Meta")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("meta");
|
||||||
|
|
||||||
|
b.Property<string>("Spell")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("spell");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("type");
|
||||||
|
|
||||||
|
b.Property<Instant>("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 =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@ -430,6 +494,10 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("expired_at");
|
.HasColumnName("expired_at");
|
||||||
|
|
||||||
|
b.Property<int>("FailedAttempts")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("failed_attempts");
|
||||||
|
|
||||||
b.Property<string>("IpAddress")
|
b.Property<string>("IpAddress")
|
||||||
.HasMaxLength(128)
|
.HasMaxLength(128)
|
||||||
.HasColumnType("character varying(128)")
|
.HasColumnType("character varying(128)")
|
||||||
@ -555,9 +623,10 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("uuid")
|
.HasColumnType("uuid")
|
||||||
.HasColumnName("group_id");
|
.HasColumnName("group_id");
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
b.Property<string>("Actor")
|
||||||
.HasColumnType("bigint")
|
.HasMaxLength(1024)
|
||||||
.HasColumnName("account_id");
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("actor");
|
||||||
|
|
||||||
b.Property<Instant?>("AffectedAt")
|
b.Property<Instant?>("AffectedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
@ -579,13 +648,10 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("updated_at");
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
b.HasKey("GroupId", "AccountId")
|
b.HasKey("GroupId", "Actor")
|
||||||
.HasName("pk_permission_group_member");
|
.HasName("pk_permission_group_members");
|
||||||
|
|
||||||
b.HasIndex("AccountId")
|
b.ToTable("permission_group_members", (string)null);
|
||||||
.HasDatabaseName("ix_permission_group_member_account_id");
|
|
||||||
|
|
||||||
b.ToTable("permission_group_member", (string)null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
||||||
@ -633,15 +699,11 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("character varying(1024)")
|
.HasColumnType("character varying(1024)")
|
||||||
.HasColumnName("key");
|
.HasColumnName("key");
|
||||||
|
|
||||||
b.Property<Guid?>("PermissionGroupId")
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasColumnName("permission_group_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
b.Property<Instant>("UpdatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("updated_at");
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
b.Property<object>("Value")
|
b.Property<JsonDocument>("Value")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasColumnName("value");
|
.HasColumnName("value");
|
||||||
@ -652,9 +714,6 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
b.HasIndex("GroupId")
|
b.HasIndex("GroupId")
|
||||||
.HasDatabaseName("ix_permission_nodes_group_id");
|
.HasDatabaseName("ix_permission_nodes_group_id");
|
||||||
|
|
||||||
b.HasIndex("PermissionGroupId")
|
|
||||||
.HasDatabaseName("ix_permission_nodes_permission_group_id");
|
|
||||||
|
|
||||||
b.HasIndex("Key", "Area", "Actor")
|
b.HasIndex("Key", "Area", "Actor")
|
||||||
.HasDatabaseName("ix_permission_nodes_key_area_actor");
|
.HasDatabaseName("ix_permission_nodes_key_area_actor");
|
||||||
|
|
||||||
@ -1231,6 +1290,16 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
b.Navigation("Account");
|
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 =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||||
@ -1337,36 +1406,22 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroupMember", b =>
|
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")
|
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group")
|
||||||
.WithMany("Members")
|
.WithMany("Members")
|
||||||
.HasForeignKey("GroupId")
|
.HasForeignKey("GroupId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasConstraintName("fk_permission_group_member_permission_groups_group_id");
|
.HasConstraintName("fk_permission_group_members_permission_groups_group_id");
|
||||||
|
|
||||||
b.Navigation("Account");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
b.Navigation("Group");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionNode", "Group")
|
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group")
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupId")
|
|
||||||
.HasConstraintName("fk_permission_nodes_permission_nodes_group_id");
|
|
||||||
|
|
||||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", null)
|
|
||||||
.WithMany("Nodes")
|
.WithMany("Nodes")
|
||||||
.HasForeignKey("PermissionGroupId")
|
.HasForeignKey("GroupId")
|
||||||
.HasConstraintName("fk_permission_nodes_permission_groups_permission_group_id");
|
.HasConstraintName("fk_permission_nodes_permission_groups_group_id");
|
||||||
|
|
||||||
b.Navigation("Group");
|
b.Navigation("Group");
|
||||||
});
|
});
|
||||||
@ -1560,8 +1615,6 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
b.Navigation("Contacts");
|
b.Navigation("Contacts");
|
||||||
|
|
||||||
b.Navigation("GroupMemberships");
|
|
||||||
|
|
||||||
b.Navigation("IncomingRelationships");
|
b.Navigation("IncomingRelationships");
|
||||||
|
|
||||||
b.Navigation("OutgoingRelationships");
|
b.Navigation("OutgoingRelationships");
|
@ -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
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class InitialMigration : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "accounts",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||||
|
nick = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||||
|
language = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||||
|
activated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
is_superuser = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_accounts", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "permission_groups",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
key = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_permission_groups", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "post_categories",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
slug = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||||
|
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_post_categories", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "post_tags",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
slug = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||||
|
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_post_tags", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "account_auth_factors",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
type = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
secret = table.Column<string>(type: "text", nullable: true),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
type = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
verified_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
content = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false),
|
||||||
|
related_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
||||||
|
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
step_remain = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
step_total = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
failed_attempts = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
blacklist_factors = table.Column<List<long>>(type: "jsonb", nullable: false),
|
||||||
|
audiences = table.Column<List<string>>(type: "jsonb", nullable: false),
|
||||||
|
scopes = table.Column<List<string>>(type: "jsonb", nullable: false),
|
||||||
|
ip_address = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||||
|
user_agent = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
|
||||||
|
device_id = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
nonce = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
||||||
|
spell = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
type = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
expires_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
affected_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: false),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
||||||
|
device_id = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
||||||
|
device_token = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
||||||
|
provider = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
last_used_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
||||||
|
topic = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
title = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
|
||||||
|
subtitle = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||||
|
content = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
||||||
|
meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: true),
|
||||||
|
priority = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
viewed_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
||||||
|
actor = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
affected_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
||||||
|
actor = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
area = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
key = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
value = table.Column<JsonDocument>(type: "jsonb", nullable: false),
|
||||||
|
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
affected_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
group_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<Guid>(type: "uuid", nullable: false),
|
||||||
|
last_granted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
challenge_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false),
|
||||||
|
first_name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
middle_name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
last_name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
bio = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
||||||
|
picture_id = table.Column<string>(type: "character varying(128)", nullable: true),
|
||||||
|
background_id = table.Column<string>(type: "character varying(128)", nullable: true),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||||
|
name = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
description = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
||||||
|
file_meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: true),
|
||||||
|
user_meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: true),
|
||||||
|
mime_type = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
hash = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
size = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
uploaded_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
uploaded_to = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||||
|
used_count = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
post_id = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
publisher_type = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||||
|
nick = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||||
|
bio = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
||||||
|
picture_id = table.Column<string>(type: "character varying(128)", nullable: true),
|
||||||
|
background_id = table.Column<string>(type: "character varying(128)", nullable: true),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
slug = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||||
|
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
description = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
||||||
|
publisher_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
title = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
|
||||||
|
description = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
||||||
|
language = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||||
|
edited_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
published_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
visibility = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
content = table.Column<string>(type: "text", nullable: true),
|
||||||
|
type = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: true),
|
||||||
|
views_unique = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
views_total = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
upvotes = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
downvotes = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
threaded_post_id = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
replied_post_id = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
forwarded_post_id = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
publisher_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
role = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
joined_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false),
|
||||||
|
posts_id = table.Column<long>(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<long>(type: "bigint", nullable: false),
|
||||||
|
posts_id = table.Column<long>(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<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
symbol = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||||
|
attitude = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
post_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_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<long>(type: "bigint", nullable: false),
|
||||||
|
tags_id = table.Column<long>(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");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json;
|
||||||
using DysonNetwork.Sphere;
|
using DysonNetwork.Sphere;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
@ -33,6 +34,10 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<Instant?>("ActivatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("activated_at");
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
b.Property<Instant>("CreatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("created_at");
|
.HasColumnName("created_at");
|
||||||
@ -167,6 +172,65 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
b.ToTable("account_contacts", (string)null);
|
b.ToTable("account_contacts", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<long?>("AccountId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("account_id");
|
||||||
|
|
||||||
|
b.Property<Instant?>("AffectedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("affected_at");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("ExpiresAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("expires_at");
|
||||||
|
|
||||||
|
b.Property<Dictionary<string, object>>("Meta")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("meta");
|
||||||
|
|
||||||
|
b.Property<string>("Spell")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("spell");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("type");
|
||||||
|
|
||||||
|
b.Property<Instant>("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 =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@ -427,6 +491,10 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("expired_at");
|
.HasColumnName("expired_at");
|
||||||
|
|
||||||
|
b.Property<int>("FailedAttempts")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("failed_attempts");
|
||||||
|
|
||||||
b.Property<string>("IpAddress")
|
b.Property<string>("IpAddress")
|
||||||
.HasMaxLength(128)
|
.HasMaxLength(128)
|
||||||
.HasColumnType("character varying(128)")
|
.HasColumnType("character varying(128)")
|
||||||
@ -552,9 +620,10 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("uuid")
|
.HasColumnType("uuid")
|
||||||
.HasColumnName("group_id");
|
.HasColumnName("group_id");
|
||||||
|
|
||||||
b.Property<long>("AccountId")
|
b.Property<string>("Actor")
|
||||||
.HasColumnType("bigint")
|
.HasMaxLength(1024)
|
||||||
.HasColumnName("account_id");
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("actor");
|
||||||
|
|
||||||
b.Property<Instant?>("AffectedAt")
|
b.Property<Instant?>("AffectedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
@ -576,13 +645,10 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("updated_at");
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
b.HasKey("GroupId", "AccountId")
|
b.HasKey("GroupId", "Actor")
|
||||||
.HasName("pk_permission_group_member");
|
.HasName("pk_permission_group_members");
|
||||||
|
|
||||||
b.HasIndex("AccountId")
|
b.ToTable("permission_group_members", (string)null);
|
||||||
.HasDatabaseName("ix_permission_group_member_account_id");
|
|
||||||
|
|
||||||
b.ToTable("permission_group_member", (string)null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
||||||
@ -630,15 +696,11 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("character varying(1024)")
|
.HasColumnType("character varying(1024)")
|
||||||
.HasColumnName("key");
|
.HasColumnName("key");
|
||||||
|
|
||||||
b.Property<Guid?>("PermissionGroupId")
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasColumnName("permission_group_id");
|
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
b.Property<Instant>("UpdatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("updated_at");
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
b.Property<object>("Value")
|
b.Property<JsonDocument>("Value")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasColumnName("value");
|
.HasColumnName("value");
|
||||||
@ -649,9 +711,6 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
b.HasIndex("GroupId")
|
b.HasIndex("GroupId")
|
||||||
.HasDatabaseName("ix_permission_nodes_group_id");
|
.HasDatabaseName("ix_permission_nodes_group_id");
|
||||||
|
|
||||||
b.HasIndex("PermissionGroupId")
|
|
||||||
.HasDatabaseName("ix_permission_nodes_permission_group_id");
|
|
||||||
|
|
||||||
b.HasIndex("Key", "Area", "Actor")
|
b.HasIndex("Key", "Area", "Actor")
|
||||||
.HasDatabaseName("ix_permission_nodes_key_area_actor");
|
.HasDatabaseName("ix_permission_nodes_key_area_actor");
|
||||||
|
|
||||||
@ -1228,6 +1287,16 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
b.Navigation("Account");
|
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 =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||||
@ -1334,36 +1403,22 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroupMember", b =>
|
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")
|
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group")
|
||||||
.WithMany("Members")
|
.WithMany("Members")
|
||||||
.HasForeignKey("GroupId")
|
.HasForeignKey("GroupId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasConstraintName("fk_permission_group_member_permission_groups_group_id");
|
.HasConstraintName("fk_permission_group_members_permission_groups_group_id");
|
||||||
|
|
||||||
b.Navigation("Account");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
b.Navigation("Group");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionNode", "Group")
|
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group")
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupId")
|
|
||||||
.HasConstraintName("fk_permission_nodes_permission_nodes_group_id");
|
|
||||||
|
|
||||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", null)
|
|
||||||
.WithMany("Nodes")
|
.WithMany("Nodes")
|
||||||
.HasForeignKey("PermissionGroupId")
|
.HasForeignKey("GroupId")
|
||||||
.HasConstraintName("fk_permission_nodes_permission_groups_permission_group_id");
|
.HasConstraintName("fk_permission_nodes_permission_groups_group_id");
|
||||||
|
|
||||||
b.Navigation("Group");
|
b.Navigation("Group");
|
||||||
});
|
});
|
||||||
@ -1557,8 +1612,6 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
b.Navigation("Contacts");
|
b.Navigation("Contacts");
|
||||||
|
|
||||||
b.Navigation("GroupMemberships");
|
|
||||||
|
|
||||||
b.Navigation("IncomingRelationships");
|
b.Navigation("IncomingRelationships");
|
||||||
|
|
||||||
b.Navigation("OutgoingRelationships");
|
b.Navigation("OutgoingRelationships");
|
||||||
|
@ -125,8 +125,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
Hosted by
|
Hosted by
|
||||||
<a
|
<a
|
||||||
@* TODO Update the project link here *@
|
href="https://github.com/Solsynth/DysonNetwork"
|
||||||
href="https://github.com/Solsynth/HyperNet.Nexus"
|
|
||||||
style="color: #c9d1d9"
|
style="color: #c9d1d9"
|
||||||
>DysonNetwork.Sphere</a>
|
>DysonNetwork.Sphere</a>
|
||||||
</div>
|
</div>
|
||||||
|
98
DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml
Normal file
98
DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
@page "/spells/{spellWord}"
|
||||||
|
@using DysonNetwork.Sphere.Account
|
||||||
|
@model DysonNetwork.Sphere.Pages.MagicSpellPage
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = null;
|
||||||
|
|
||||||
|
var spell = ViewData["Spell"] as MagicSpell;
|
||||||
|
}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<title>Solar Network Magic Spell</title>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: #2d2d2d;
|
||||||
|
font-family: "Roboto Mono", monospace;
|
||||||
|
color: #c9d1d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parent {
|
||||||
|
padding: 20px;
|
||||||
|
max-width: 480px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: #ffffff;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 11px;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-product {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.g-recaptcha {
|
||||||
|
display: inline-block; /* Adjust as needed */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="parent">
|
||||||
|
<div class="container">
|
||||||
|
<h1>Magic Spell</h1>
|
||||||
|
@if (spell == null)
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
<p style="color: yellow;">The spell was expired or not exists.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
<p style="color: green;">The spell was applied successfully!</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<div class="footer-product">Solar Network</div>
|
||||||
|
<a
|
||||||
|
href="https://solsynth.dev"
|
||||||
|
style="color: #c9d1d9; text-decoration: none"
|
||||||
|
>Solsynth LLC</a>
|
||||||
|
© @DateTime.Now.Year<br/>
|
||||||
|
Powered by
|
||||||
|
<a
|
||||||
|
href="https://github.com/Solsynth/DysonNetwork"
|
||||||
|
style="color: #c9d1d9"
|
||||||
|
>DysonNetwork.Sphere</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
24
DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml.cs
Normal file
24
DysonNetwork.Sphere/Pages/MagicSpellPage.cshtml.cs
Normal file
@ -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<ActionResult> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Text.Json;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NodaTime;
|
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
|
/// 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.
|
/// expect the member of that permission group inherent the permission from the group.
|
||||||
[Index(nameof(Key), nameof(Area), nameof(Actor))]
|
[Index(nameof(Key), nameof(Area), nameof(Actor))]
|
||||||
public class PermissionNode : ModelBase
|
public class PermissionNode : ModelBase, IDisposable
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
[MaxLength(1024)] public string Actor { get; set; } = null!;
|
[MaxLength(1024)] public string Actor { get; set; } = null!;
|
||||||
[MaxLength(1024)] public string Area { get; set; } = null!;
|
[MaxLength(1024)] public string Area { get; set; } = null!;
|
||||||
[MaxLength(1024)] public string Key { 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? ExpiredAt { get; set; } = null;
|
||||||
public Instant? AffectedAt { get; set; } = null;
|
public Instant? AffectedAt { get; set; } = null;
|
||||||
|
|
||||||
public Guid? GroupId { 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
|
public class PermissionGroup : ModelBase
|
||||||
@ -44,10 +51,9 @@ public class PermissionGroup : ModelBase
|
|||||||
public class PermissionGroupMember : ModelBase
|
public class PermissionGroupMember : ModelBase
|
||||||
{
|
{
|
||||||
public Guid GroupId { get; set; }
|
public Guid GroupId { get; set; }
|
||||||
public long AccountId { get; set; }
|
|
||||||
public PermissionGroup Group { get; set; } = null!;
|
public PermissionGroup Group { get; set; } = null!;
|
||||||
public Account.Account Account { get; set; } = null!;
|
[MaxLength(1024)] public string Actor { get; set; } = null!;
|
||||||
|
|
||||||
public Instant? ExpiredAt { get; set; } = null;
|
public Instant? ExpiredAt { get; set; }
|
||||||
public Instant? AffectedAt { get; set; } = null;
|
public Instant? AffectedAt { get; set; }
|
||||||
}
|
}
|
51
DysonNetwork.Sphere/Permission/PermissionMiddleware.cs
Normal file
51
DysonNetwork.Sphere/Permission/PermissionMiddleware.cs
Normal file
@ -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<RequiredPermissionAttribute>()
|
||||||
|
.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<bool>(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);
|
||||||
|
}
|
||||||
|
}
|
126
DysonNetwork.Sphere/Permission/PermissionService.cs
Normal file
126
DysonNetwork.Sphere/Permission/PermissionService.cs
Normal file
@ -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<T?> GetPermissionAsync<T>(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<T>(permission.Value) : default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PermissionNode> AddPermissionNode<T>(
|
||||||
|
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<PermissionNode> AddPermissionNodeToGroup<T>(
|
||||||
|
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<T>(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<T>(JsonDocument json)
|
||||||
|
{
|
||||||
|
return JsonSerializer.Deserialize<T>(json.RootElement.GetRawText());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JsonDocument _SerializePermissionValue<T>(T obj)
|
||||||
|
{
|
||||||
|
var str = JsonSerializer.Serialize(obj);
|
||||||
|
return JsonDocument.Parse(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PermissionNode NewPermissionNode<T>(string actor, string area, string key, T value)
|
||||||
|
{
|
||||||
|
return new PermissionNode
|
||||||
|
{
|
||||||
|
Actor = actor,
|
||||||
|
Area = area,
|
||||||
|
Key = key,
|
||||||
|
Value = _SerializePermissionValue(value),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Casbin;
|
using Casbin;
|
||||||
|
using DysonNetwork.Sphere.Permission;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
@ -8,7 +9,7 @@ namespace DysonNetwork.Sphere.Post;
|
|||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/posts")]
|
[Route("/posts")]
|
||||||
public class PostController(AppDatabase db, PostService ps, IEnforcer enforcer) : ControllerBase
|
public class PostController(AppDatabase db, PostService ps) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<List<Post>>> ListPosts([FromQuery] int offset = 0, [FromQuery] int take = 20)
|
public async Task<ActionResult<List<Post>>> ListPosts([FromQuery] int offset = 0, [FromQuery] int take = 20)
|
||||||
@ -118,14 +119,13 @@ public class PostController(AppDatabase db, PostService ps, IEnforcer enforcer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
|
[RequiredPermission("global", "posts.create")]
|
||||||
public async Task<ActionResult<Post>> CreatePost(
|
public async Task<ActionResult<Post>> CreatePost(
|
||||||
[FromBody] PostRequest request,
|
[FromBody] PostRequest request,
|
||||||
[FromHeader(Name = "X-Pub")] string? publisherName
|
[FromHeader(Name = "X-Pub")] string? publisherName
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
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;
|
Publisher? publisher;
|
||||||
if (publisherName is null)
|
if (publisherName is null)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Casbin;
|
using Casbin;
|
||||||
|
using DysonNetwork.Sphere.Permission;
|
||||||
using DysonNetwork.Sphere.Storage;
|
using DysonNetwork.Sphere.Storage;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@ -10,7 +11,7 @@ namespace DysonNetwork.Sphere.Post;
|
|||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/publishers")]
|
[Route("/publishers")]
|
||||||
public class PublisherController(AppDatabase db, PublisherService ps, FileService fs, IEnforcer enforcer)
|
public class PublisherController(AppDatabase db, PublisherService ps, FileService fs)
|
||||||
: ControllerBase
|
: ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet("{name}")]
|
[HttpGet("{name}")]
|
||||||
@ -167,12 +168,10 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic
|
|||||||
|
|
||||||
[HttpPost("individual")]
|
[HttpPost("individual")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
|
[RequiredPermission("global", "publishers.create")]
|
||||||
public async Task<ActionResult<Publisher>> CreatePublisherIndividual(PublisherRequest request)
|
public async Task<ActionResult<Publisher>> CreatePublisherIndividual(PublisherRequest request)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
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 takenName = request.Name ?? currentUser.Name;
|
||||||
var duplicateNameCount = await db.Publishers
|
var duplicateNameCount = await db.Publishers
|
||||||
|
@ -8,6 +8,7 @@ using Casbin.Persist.Adapter.EFCore;
|
|||||||
using DysonNetwork.Sphere;
|
using DysonNetwork.Sphere;
|
||||||
using DysonNetwork.Sphere.Account;
|
using DysonNetwork.Sphere.Account;
|
||||||
using DysonNetwork.Sphere.Auth;
|
using DysonNetwork.Sphere.Auth;
|
||||||
|
using DysonNetwork.Sphere.Permission;
|
||||||
using DysonNetwork.Sphere.Post;
|
using DysonNetwork.Sphere.Post;
|
||||||
using DysonNetwork.Sphere.Storage;
|
using DysonNetwork.Sphere.Storage;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@ -45,22 +46,6 @@ builder.Services.AddControllers().AddJsonOptions(options =>
|
|||||||
});
|
});
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
|
|
||||||
// Casbin permissions
|
|
||||||
|
|
||||||
var casbinDbContext = new CasbinDbContext<int>(
|
|
||||||
new DbContextOptionsBuilder<CasbinDbContext<int>>()
|
|
||||||
.UseNpgsql(builder.Configuration.GetConnectionString("Guard"))
|
|
||||||
.Options
|
|
||||||
);
|
|
||||||
var casbinEfcore = new EFCoreAdapter<int>(casbinDbContext);
|
|
||||||
casbinDbContext.Database.EnsureCreated();
|
|
||||||
var casbinEncofcer = new Enforcer("Casbin.conf", casbinEfcore);
|
|
||||||
casbinEncofcer.EnableCache(true);
|
|
||||||
casbinEncofcer.LoadPolicy();
|
|
||||||
|
|
||||||
builder.Services.AddSingleton<IEnforcer>(casbinEncofcer);
|
|
||||||
builder.Services.AddSingleton<IAuthorizationHandler, CasbinAuthorizationHandler>();
|
|
||||||
|
|
||||||
// Other pipelines
|
// Other pipelines
|
||||||
|
|
||||||
builder.Services.AddRateLimiter(o => o.AddFixedWindowLimiter(policyName: "fixed", opts =>
|
builder.Services.AddRateLimiter(o => o.AddFixedWindowLimiter(policyName: "fixed", opts =>
|
||||||
@ -129,7 +114,10 @@ builder.Services.AddSwaggerGen(options =>
|
|||||||
});
|
});
|
||||||
builder.Services.AddOpenApi();
|
builder.Services.AddOpenApi();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<EmailService>();
|
||||||
|
builder.Services.AddScoped<PermissionService>();
|
||||||
builder.Services.AddScoped<AccountService>();
|
builder.Services.AddScoped<AccountService>();
|
||||||
|
builder.Services.AddScoped<MagicSpellService>();
|
||||||
builder.Services.AddScoped<NotificationService>();
|
builder.Services.AddScoped<NotificationService>();
|
||||||
builder.Services.AddScoped<AuthService>();
|
builder.Services.AddScoped<AuthService>();
|
||||||
builder.Services.AddScoped<FileService>();
|
builder.Services.AddScoped<FileService>();
|
||||||
@ -163,7 +151,7 @@ var app = builder.Build();
|
|||||||
using (var scope = app.Services.CreateScope())
|
using (var scope = app.Services.CreateScope())
|
||||||
{
|
{
|
||||||
var db = scope.ServiceProvider.GetRequiredService<AppDatabase>();
|
var db = scope.ServiceProvider.GetRequiredService<AppDatabase>();
|
||||||
db.Database.Migrate();
|
await db.Database.MigrateAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.MapOpenApi();
|
app.MapOpenApi();
|
||||||
@ -189,6 +177,7 @@ app.UseRateLimiter();
|
|||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.UseMiddleware<UserInfoMiddleware>();
|
app.UseMiddleware<UserInfoMiddleware>();
|
||||||
|
app.UseMiddleware<PermissionMiddleware>();
|
||||||
|
|
||||||
app.MapControllers().RequireRateLimiting("fixed");
|
app.MapControllers().RequireRateLimiting("fixed");
|
||||||
app.MapStaticAssets().RequireRateLimiting("fixed");
|
app.MapStaticAssets().RequireRateLimiting("fixed");
|
||||||
|
@ -7,8 +7,7 @@
|
|||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"App": "Host=localhost;Port=5432;Database=dyson_network;Username=postgres;Password=postgres",
|
"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"
|
|
||||||
},
|
},
|
||||||
"Authentication": {
|
"Authentication": {
|
||||||
"Schemes": {
|
"Schemes": {
|
||||||
@ -55,11 +54,20 @@
|
|||||||
"Production": true,
|
"Production": true,
|
||||||
"Google": "path/to/config.json",
|
"Google": "path/to/config.json",
|
||||||
"Apple": {
|
"Apple": {
|
||||||
"PrivateKey": "path/to/cert.p8",
|
"PrivateKey": "path/to/cert.p8",
|
||||||
"PrivateKeyId": "",
|
"PrivateKeyId": "",
|
||||||
"TeamId": "",
|
"TeamId": "",
|
||||||
"BundleIdentifier": ""
|
"BundleIdentifier": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Email": {
|
||||||
|
"Server": "",
|
||||||
|
"Port": 465,
|
||||||
|
"Username": "",
|
||||||
|
"Password": "",
|
||||||
|
"FromAddress": "",
|
||||||
|
"FromName": "",
|
||||||
|
"SubjectPrefix": "Solar Network"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AApnSender_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6aadc2cf048f477d8636fb2def7b73648200_003Fc5_003F2a1973a9_003FApnSender_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AApnSender_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6aadc2cf048f477d8636fb2def7b73648200_003Fc5_003F2a1973a9_003FApnSender_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthenticationMiddleware_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe49de78932194d52a02b07486c6d023a24600_003F2f_003F7ab1cc57_003FAuthenticationMiddleware_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthenticationMiddleware_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe49de78932194d52a02b07486c6d023a24600_003F2f_003F7ab1cc57_003FAuthenticationMiddleware_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthorizationAppBuilderExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2ff26593f91746d7a53418a46dc419d1f200_003F4b_003F56550da2_003FAuthorizationAppBuilderExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthorizationAppBuilderExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2ff26593f91746d7a53418a46dc419d1f200_003F4b_003F56550da2_003FAuthorizationAppBuilderExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABodyBuilder_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fc5c8aba04a29d49c65d772c9ffcd93ac7eb38ccbb49a5f506518a0b9bdcaa75_003FBodyBuilder_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABucketArgs_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fd515fb889657fcdcace3fed90735057b458ff9e0bb60bded7c8fe8b3a4673c_003FBucketArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABucketArgs_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fd515fb889657fcdcace3fed90735057b458ff9e0bb60bded7c8fe8b3a4673c_003FBucketArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AChapterData_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffef366b36a224d469ff150d30f9a866d23c00_003Fe6_003F64a6c0f7_003FChapterData_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AChapterData_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffef366b36a224d469ff150d30f9a866d23c00_003Fe6_003F64a6c0f7_003FChapterData_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AClaim_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7fdc52b6e574ae7b9822133be91162a15800_003Ff7_003Feebffd8d_003FClaim_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AClaim_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7fdc52b6e574ae7b9822133be91162a15800_003Ff7_003Feebffd8d_003FClaim_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
@ -28,6 +29,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIServiceCollectionQuartzConfigurator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1edbd6e24d7b430fabce72177269baa19200_003F67_003Faee36f5b_003FIServiceCollectionQuartzConfigurator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIServiceCollectionQuartzConfigurator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1edbd6e24d7b430fabce72177269baa19200_003F67_003Faee36f5b_003FIServiceCollectionQuartzConfigurator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AITusStore_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bb08a178b5b43c5bac20a5a54159a5b2a800_003Fb1_003F7e861de5_003FITusStore_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AITusStore_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bb08a178b5b43c5bac20a5a54159a5b2a800_003Fb1_003F7e861de5_003FITusStore_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKestrelServerLimits_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1e2e5dfcafad4407b569dd5df56a2fbf274e00_003Fa4_003F39445f62_003FKestrelServerLimits_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKestrelServerLimits_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1e2e5dfcafad4407b569dd5df56a2fbf274e00_003Fa4_003F39445f62_003FKestrelServerLimits_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMailboxAddress_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8e03e47c46b7469f97abc40667cbcf9b133000_003Fa6_003F83324248_003FMailboxAddress_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMediaAnalysis_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffef366b36a224d469ff150d30f9a866d23c00_003Fd7_003F5c138865_003FMediaAnalysis_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMediaAnalysis_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffef366b36a224d469ff150d30f9a866d23c00_003Fd7_003F5c138865_003FMediaAnalysis_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMicrosoftDependencyInjectionJobFactory_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1edbd6e24d7b430fabce72177269baa19200_003Fa8_003F91b091de_003FMicrosoftDependencyInjectionJobFactory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMicrosoftDependencyInjectionJobFactory_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1edbd6e24d7b430fabce72177269baa19200_003Fa8_003F91b091de_003FMicrosoftDependencyInjectionJobFactory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANotFoundResult_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0b5acdd962e549369896cece0026e556214600_003F28_003F290250f5_003FNotFoundResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANotFoundResult_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0b5acdd962e549369896cece0026e556214600_003F28_003F290250f5_003FNotFoundResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user