✨ 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 Nick { get; set; } = string.Empty;
|
||||
[MaxLength(32)] public string Language { get; set; } = string.Empty;
|
||||
public Instant? ActivatedAt { get; set; }
|
||||
public bool IsSuperuser { get; set; } = false;
|
||||
|
||||
public Profile Profile { get; set; } = null!;
|
||||
@ -24,8 +25,6 @@ public class Account : ModelBase
|
||||
|
||||
[JsonIgnore] public ICollection<Relationship> OutgoingRelationships { 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
|
||||
|
@ -1,15 +1,23 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Sphere.Auth;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Sphere.Account;
|
||||
|
||||
[ApiController]
|
||||
[Route("/accounts")]
|
||||
public class AccountController(AppDatabase db, FileService fs, IMemoryCache memCache) : ControllerBase
|
||||
public class AccountController(
|
||||
AppDatabase db,
|
||||
FileService fs,
|
||||
AuthService auth,
|
||||
MagicSpellService spells,
|
||||
IMemoryCache memCache
|
||||
) : ControllerBase
|
||||
{
|
||||
[HttpGet("{name}")]
|
||||
[ProducesResponseType<Account>(StatusCodes.Status200OK)]
|
||||
@ -39,6 +47,10 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
||||
[MinLength(4)]
|
||||
[MaxLength(128)]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(128)] public string Language { get; set; } = "en";
|
||||
|
||||
[Required] public string CaptchaToken { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
@ -46,6 +58,8 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<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();
|
||||
if (dupeNameCount > 0)
|
||||
return BadRequest("The name is already taken.");
|
||||
@ -54,6 +68,7 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
||||
{
|
||||
Name = request.Name,
|
||||
Nick = request.Nick,
|
||||
Language = request.Language,
|
||||
Contacts = new List<AccountContact>
|
||||
{
|
||||
new()
|
||||
@ -75,6 +90,18 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
||||
|
||||
await db.Accounts.AddAsync(account);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var spell = await spells.CreateMagicSpell(
|
||||
account,
|
||||
MagicSpellType.AccountActivation,
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ "contact_method", account.Contacts.First().Content }
|
||||
},
|
||||
expiredAt: SystemClock.Instance.GetCurrentInstant().Plus(Duration.FromDays(7))
|
||||
);
|
||||
spells.NotifyMagicSpell(spell);
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
@ -110,7 +137,7 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
||||
|
||||
if (request.Nick is not null) account.Nick = request.Nick;
|
||||
if (request.Language is not null) account.Language = request.Language;
|
||||
|
||||
|
||||
memCache.Remove($"user_${account.Id}");
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
@ -171,9 +198,9 @@ public class AccountController(AppDatabase db, FileService fs, IMemoryCache memC
|
||||
|
||||
db.Update(profile);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
|
||||
memCache.Remove($"user_${userId}");
|
||||
|
||||
|
||||
return profile;
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
using Casbin;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Sphere.Account;
|
||||
|
||||
public class AccountService(AppDatabase db, IEnforcer enforcer)
|
||||
public class AccountService(AppDatabase db, PermissionService pm)
|
||||
{
|
||||
public async Task<Account?> LookupAccount(string probe)
|
||||
{
|
||||
@ -145,18 +146,18 @@ public class AccountService(AppDatabase db, IEnforcer enforcer)
|
||||
// others: use the default permissions by design
|
||||
|
||||
var domain = $"user:{relationship.AccountId.ToString()}";
|
||||
var target = relationship.RelatedId.ToString();
|
||||
var target = $"user:{relationship.RelatedId.ToString()}";
|
||||
|
||||
await enforcer.DeleteRolesForUserAsync(target, domain);
|
||||
await pm.RemovePermissionNode(target, domain, "*");
|
||||
|
||||
string role = relationship.Status switch
|
||||
bool? value = relationship.Status switch
|
||||
{
|
||||
RelationshipStatus.Friends => "friends",
|
||||
RelationshipStatus.Blocked => "blocked",
|
||||
_ => "default" // fallback role
|
||||
RelationshipStatus.Friends => true,
|
||||
RelationshipStatus.Blocked => false,
|
||||
_ => null,
|
||||
};
|
||||
if (role == "default") return;
|
||||
if (value is null) return;
|
||||
|
||||
await enforcer.AddRoleForUserAsync(target, role, domain);
|
||||
await pm.AddPermissionNode(target, domain, "*", value);
|
||||
}
|
||||
}
|
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 DysonNetwork.Sphere.Permission;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using NodaTime;
|
||||
@ -19,18 +20,24 @@ public class AppDatabase(
|
||||
IConfiguration configuration
|
||||
) : DbContext(options)
|
||||
{
|
||||
public DbSet<Permission.PermissionNode> PermissionNodes { get; set; } = null!;
|
||||
public DbSet<Permission.PermissionGroup> PermissionGroups { get; set; } = null!;
|
||||
public DbSet<PermissionNode> PermissionNodes { 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.Profile> AccountProfiles { get; set; }
|
||||
public DbSet<Account.AccountContact> AccountContacts { get; set; }
|
||||
public DbSet<Account.AccountAuthFactor> AccountAuthFactors { 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.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<Post.Publisher> Publishers { get; set; }
|
||||
public DbSet<Post.PublisherMember> PublisherMembers { get; set; }
|
||||
public DbSet<Post.Post> Posts { get; set; }
|
||||
@ -51,6 +58,25 @@ public class AppDatabase(
|
||||
opt => opt.UseNodaTime()
|
||||
).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);
|
||||
}
|
||||
|
||||
@ -59,19 +85,13 @@ public class AppDatabase(
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.Entity<Permission.PermissionGroupMember>()
|
||||
.HasKey(pg => new { pg.GroupId, pg.AccountId })
|
||||
.HasName("permission_group_members");
|
||||
.HasKey(pg => new { pg.GroupId, pg.Actor });
|
||||
modelBuilder.Entity<Permission.PermissionGroupMember>()
|
||||
.HasOne(pg => pg.Group)
|
||||
.WithMany(g => g.Members)
|
||||
.HasForeignKey(pg => pg.GroupId)
|
||||
.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>()
|
||||
.HasOne(a => a.Profile)
|
||||
.WithOne(p => p.Account)
|
||||
@ -87,7 +107,7 @@ public class AppDatabase(
|
||||
.HasOne(r => r.Related)
|
||||
.WithMany(a => a.IncomingRelationships)
|
||||
.HasForeignKey(r => r.RelatedId);
|
||||
|
||||
|
||||
modelBuilder.Entity<Post.PublisherMember>()
|
||||
.HasKey(pm => new { pm.PublisherId, pm.AccountId });
|
||||
modelBuilder.Entity<Post.PublisherMember>()
|
||||
@ -100,7 +120,7 @@ public class AppDatabase(
|
||||
.WithMany()
|
||||
.HasForeignKey(pm => pm.AccountId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
|
||||
modelBuilder.Entity<Post.Post>()
|
||||
.HasOne(p => p.ThreadedPost)
|
||||
.WithOne()
|
||||
@ -113,7 +133,7 @@ public class AppDatabase(
|
||||
modelBuilder.Entity<Post.Post>()
|
||||
.HasOne(p => p.ForwardedPost)
|
||||
.WithMany()
|
||||
.HasForeignKey(p => p.ForwardedPostId)
|
||||
.HasForeignKey(p => p.ForwardedPostId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
modelBuilder.Entity<Post.Post>()
|
||||
.HasMany(p => p.Tags)
|
||||
|
@ -15,8 +15,7 @@ public class AuthController(
|
||||
AppDatabase db,
|
||||
AccountService accounts,
|
||||
AuthService auth,
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory
|
||||
IConfiguration configuration
|
||||
) : ControllerBase
|
||||
{
|
||||
public class ChallengeRequest
|
||||
@ -218,49 +217,7 @@ public class AuthController(
|
||||
[HttpPost("captcha")]
|
||||
public async Task<ActionResult> ValidateCaptcha([FromBody] string token)
|
||||
{
|
||||
var provider = configuration.GetSection("Captcha")["Provider"]?.ToLower();
|
||||
var apiKey = configuration.GetSection("Captcha")["ApiKey"];
|
||||
var apiSecret = configuration.GetSection("Captcha")["ApiSecret"];
|
||||
|
||||
var client = httpClientFactory.CreateClient();
|
||||
|
||||
switch (provider)
|
||||
{
|
||||
case "cloudflare":
|
||||
var content = new StringContent($"secret={apiSecret}&response={token}", System.Text.Encoding.UTF8,
|
||||
"application/x-www-form-urlencoded");
|
||||
var response = await client.PostAsync("https://challenges.cloudflare.com/turnstile/v0/siteverify",
|
||||
content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
var cfResult = JsonSerializer.Deserialize<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.");
|
||||
}
|
||||
var result = await auth.ValidateCaptcha(token);
|
||||
return result ? Ok() : BadRequest();
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using Casbin;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
@ -15,68 +16,43 @@ public class SignedTokenPair
|
||||
public Instant ExpiredAt { get; set; }
|
||||
}
|
||||
|
||||
public class AuthService(AppDatabase db, IConfiguration config, IEnforcer enforcer)
|
||||
public class AuthService(IConfiguration config, IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
public async Task<bool> AssignRoleToUserAsync(string user, string role, string domain = "global")
|
||||
public async Task<bool> ValidateCaptcha(string token)
|
||||
{
|
||||
var added = await enforcer.AddGroupingPolicyAsync(user, role, domain);
|
||||
if (added) await enforcer.SavePolicyAsync();
|
||||
return added;
|
||||
}
|
||||
var provider = config.GetSection("Captcha")["Provider"]?.ToLower();
|
||||
var apiSecret = config.GetSection("Captcha")["ApiSecret"];
|
||||
|
||||
public async Task<bool> AddPermissionToUserAsync(string user, string domain, string obj, string act)
|
||||
{
|
||||
var added = await enforcer.AddPolicyAsync(user, domain, obj, act);
|
||||
if (added) await enforcer.SavePolicyAsync();
|
||||
return added;
|
||||
}
|
||||
|
||||
public async Task<bool> RemovePermissionFromUserAsync(string user, string domain, string obj, string act)
|
||||
{
|
||||
var removed = await enforcer.RemovePolicyAsync(user, domain, obj, act);
|
||||
if (removed) await enforcer.SavePolicyAsync();
|
||||
return removed;
|
||||
}
|
||||
var client = httpClientFactory.CreateClient();
|
||||
|
||||
public async Task<bool> CreateRoleAsync(string role, string domain, IEnumerable<(string obj, string act)> permissions)
|
||||
{
|
||||
bool anyAdded = false;
|
||||
foreach (var (obj, act) in permissions)
|
||||
switch (provider)
|
||||
{
|
||||
var added = await enforcer.AddPolicyAsync(role, domain, obj, act);
|
||||
if (added) anyAdded = true;
|
||||
}
|
||||
case "cloudflare":
|
||||
var content = new StringContent($"secret={apiSecret}&response={token}", System.Text.Encoding.UTF8,
|
||||
"application/x-www-form-urlencoded");
|
||||
var response = await client.PostAsync("https://challenges.cloudflare.com/turnstile/v0/siteverify",
|
||||
content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
if (anyAdded) await enforcer.SavePolicyAsync();
|
||||
return anyAdded;
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
var cfResult = JsonSerializer.Deserialize<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.");
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var privateKeyPem = File.ReadAllText(config["Jwt:PrivateKeyPath"]!);
|
||||
@ -98,9 +74,9 @@ public class AuthService(AppDatabase db, IConfiguration config, IEnforcer enforc
|
||||
expires: DateTime.Now.AddDays(30),
|
||||
signingCredentials: creds
|
||||
);
|
||||
|
||||
|
||||
session.Challenge.Scopes.ForEach(c => claims.Add(new Claim("scope", c)));
|
||||
if(session.Account.IsSuperuser) claims.Add(new Claim("is_superuser", "1"));
|
||||
if (session.Account.IsSuperuser) claims.Add(new Claim("is_superuser", "1"));
|
||||
var accessTokenClaims = new JwtSecurityToken(
|
||||
issuer: "solar-network",
|
||||
audience: string.Join(',', session.Challenge.Audiences),
|
||||
|
@ -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 int StepRemain { 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<string> Audiences { 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="EFCore.NamingConventions" Version="9.0.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.OpenApi" Version="9.0.2" />
|
||||
<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 />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Sphere;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
@ -14,8 +15,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDatabase))]
|
||||
[Migration("20250427161252_AddPermission")]
|
||||
partial class AddPermission
|
||||
[Migration("20250429115700_InitialMigration")]
|
||||
partial class InitialMigration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
@ -36,6 +37,10 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<Instant?>("ActivatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("activated_at");
|
||||
|
||||
b.Property<Instant>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at");
|
||||
@ -170,6 +175,65 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.ToTable("account_contacts", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b =>
|
||||
{
|
||||
b.Property<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 =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@ -430,6 +494,10 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("expired_at");
|
||||
|
||||
b.Property<int>("FailedAttempts")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("failed_attempts");
|
||||
|
||||
b.Property<string>("IpAddress")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)")
|
||||
@ -555,9 +623,10 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("group_id");
|
||||
|
||||
b.Property<long>("AccountId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("account_id");
|
||||
b.Property<string>("Actor")
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("character varying(1024)")
|
||||
.HasColumnName("actor");
|
||||
|
||||
b.Property<Instant?>("AffectedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
@ -579,13 +648,10 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.HasKey("GroupId", "AccountId")
|
||||
.HasName("pk_permission_group_member");
|
||||
b.HasKey("GroupId", "Actor")
|
||||
.HasName("pk_permission_group_members");
|
||||
|
||||
b.HasIndex("AccountId")
|
||||
.HasDatabaseName("ix_permission_group_member_account_id");
|
||||
|
||||
b.ToTable("permission_group_member", (string)null);
|
||||
b.ToTable("permission_group_members", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
||||
@ -633,15 +699,11 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
.HasColumnType("character varying(1024)")
|
||||
.HasColumnName("key");
|
||||
|
||||
b.Property<Guid?>("PermissionGroupId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("permission_group_id");
|
||||
|
||||
b.Property<Instant>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.Property<object>("Value")
|
||||
b.Property<JsonDocument>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("value");
|
||||
@ -652,9 +714,6 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.HasIndex("GroupId")
|
||||
.HasDatabaseName("ix_permission_nodes_group_id");
|
||||
|
||||
b.HasIndex("PermissionGroupId")
|
||||
.HasDatabaseName("ix_permission_nodes_permission_group_id");
|
||||
|
||||
b.HasIndex("Key", "Area", "Actor")
|
||||
.HasDatabaseName("ix_permission_nodes_key_area_actor");
|
||||
|
||||
@ -1231,6 +1290,16 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.Navigation("Account");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
.WithMany()
|
||||
.HasForeignKey("AccountId")
|
||||
.HasConstraintName("fk_magic_spells_accounts_account_id");
|
||||
|
||||
b.Navigation("Account");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
@ -1337,36 +1406,22 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroupMember", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
.WithMany("GroupMemberships")
|
||||
.HasForeignKey("AccountId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_permission_group_member_accounts_account_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group")
|
||||
.WithMany("Members")
|
||||
.HasForeignKey("GroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_permission_group_member_permission_groups_group_id");
|
||||
|
||||
b.Navigation("Account");
|
||||
.HasConstraintName("fk_permission_group_members_permission_groups_group_id");
|
||||
|
||||
b.Navigation("Group");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionNode", "Group")
|
||||
.WithMany()
|
||||
.HasForeignKey("GroupId")
|
||||
.HasConstraintName("fk_permission_nodes_permission_nodes_group_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", null)
|
||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group")
|
||||
.WithMany("Nodes")
|
||||
.HasForeignKey("PermissionGroupId")
|
||||
.HasConstraintName("fk_permission_nodes_permission_groups_permission_group_id");
|
||||
.HasForeignKey("GroupId")
|
||||
.HasConstraintName("fk_permission_nodes_permission_groups_group_id");
|
||||
|
||||
b.Navigation("Group");
|
||||
});
|
||||
@ -1560,8 +1615,6 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
|
||||
b.Navigation("Contacts");
|
||||
|
||||
b.Navigation("GroupMemberships");
|
||||
|
||||
b.Navigation("IncomingRelationships");
|
||||
|
||||
b.Navigation("OutgoingRelationships");
|
@ -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 />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Sphere;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
@ -33,6 +34,10 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<Instant?>("ActivatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("activated_at");
|
||||
|
||||
b.Property<Instant>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at");
|
||||
@ -167,6 +172,65 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.ToTable("account_contacts", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b =>
|
||||
{
|
||||
b.Property<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 =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@ -427,6 +491,10 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("expired_at");
|
||||
|
||||
b.Property<int>("FailedAttempts")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("failed_attempts");
|
||||
|
||||
b.Property<string>("IpAddress")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)")
|
||||
@ -552,9 +620,10 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("group_id");
|
||||
|
||||
b.Property<long>("AccountId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("account_id");
|
||||
b.Property<string>("Actor")
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("character varying(1024)")
|
||||
.HasColumnName("actor");
|
||||
|
||||
b.Property<Instant?>("AffectedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
@ -576,13 +645,10 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.HasKey("GroupId", "AccountId")
|
||||
.HasName("pk_permission_group_member");
|
||||
b.HasKey("GroupId", "Actor")
|
||||
.HasName("pk_permission_group_members");
|
||||
|
||||
b.HasIndex("AccountId")
|
||||
.HasDatabaseName("ix_permission_group_member_account_id");
|
||||
|
||||
b.ToTable("permission_group_member", (string)null);
|
||||
b.ToTable("permission_group_members", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
||||
@ -630,15 +696,11 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
.HasColumnType("character varying(1024)")
|
||||
.HasColumnName("key");
|
||||
|
||||
b.Property<Guid?>("PermissionGroupId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("permission_group_id");
|
||||
|
||||
b.Property<Instant>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.Property<object>("Value")
|
||||
b.Property<JsonDocument>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("value");
|
||||
@ -649,9 +711,6 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.HasIndex("GroupId")
|
||||
.HasDatabaseName("ix_permission_nodes_group_id");
|
||||
|
||||
b.HasIndex("PermissionGroupId")
|
||||
.HasDatabaseName("ix_permission_nodes_permission_group_id");
|
||||
|
||||
b.HasIndex("Key", "Area", "Actor")
|
||||
.HasDatabaseName("ix_permission_nodes_key_area_actor");
|
||||
|
||||
@ -1228,6 +1287,16 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.Navigation("Account");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
.WithMany()
|
||||
.HasForeignKey("AccountId")
|
||||
.HasConstraintName("fk_magic_spells_accounts_account_id");
|
||||
|
||||
b.Navigation("Account");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
@ -1334,36 +1403,22 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroupMember", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
.WithMany("GroupMemberships")
|
||||
.HasForeignKey("AccountId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_permission_group_member_accounts_account_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group")
|
||||
.WithMany("Members")
|
||||
.HasForeignKey("GroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_permission_group_member_permission_groups_group_id");
|
||||
|
||||
b.Navigation("Account");
|
||||
.HasConstraintName("fk_permission_group_members_permission_groups_group_id");
|
||||
|
||||
b.Navigation("Group");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionNode", "Group")
|
||||
.WithMany()
|
||||
.HasForeignKey("GroupId")
|
||||
.HasConstraintName("fk_permission_nodes_permission_nodes_group_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", null)
|
||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group")
|
||||
.WithMany("Nodes")
|
||||
.HasForeignKey("PermissionGroupId")
|
||||
.HasConstraintName("fk_permission_nodes_permission_groups_permission_group_id");
|
||||
.HasForeignKey("GroupId")
|
||||
.HasConstraintName("fk_permission_nodes_permission_groups_group_id");
|
||||
|
||||
b.Navigation("Group");
|
||||
});
|
||||
@ -1557,8 +1612,6 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
|
||||
b.Navigation("Contacts");
|
||||
|
||||
b.Navigation("GroupMemberships");
|
||||
|
||||
b.Navigation("IncomingRelationships");
|
||||
|
||||
b.Navigation("OutgoingRelationships");
|
||||
|
@ -125,8 +125,7 @@
|
||||
<br/>
|
||||
Hosted by
|
||||
<a
|
||||
@* TODO Update the project link here *@
|
||||
href="https://github.com/Solsynth/HyperNet.Nexus"
|
||||
href="https://github.com/Solsynth/DysonNetwork"
|
||||
style="color: #c9d1d9"
|
||||
>DysonNetwork.Sphere</a>
|
||||
</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.Schema;
|
||||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json;
|
||||
using NodaTime;
|
||||
@ -18,18 +19,24 @@ namespace DysonNetwork.Sphere.Permission;
|
||||
/// and when the permission node has a GroupId, the actor will be set to the group, but it won't work on checking
|
||||
/// expect the member of that permission group inherent the permission from the group.
|
||||
[Index(nameof(Key), nameof(Area), nameof(Actor))]
|
||||
public class PermissionNode : ModelBase
|
||||
public class PermissionNode : ModelBase, IDisposable
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
[MaxLength(1024)] public string Actor { get; set; } = null!;
|
||||
[MaxLength(1024)] public string Area { get; set; } = null!;
|
||||
[MaxLength(1024)] public string Key { get; set; } = null!;
|
||||
[Column(TypeName = "jsonb")] public object Value { get; set; } = null!;
|
||||
[Column(TypeName = "jsonb")] public JsonDocument Value { get; set; } = null!;
|
||||
public Instant? ExpiredAt { get; set; } = null;
|
||||
public Instant? AffectedAt { get; set; } = null;
|
||||
|
||||
|
||||
public Guid? GroupId { get; set; } = null;
|
||||
[JsonIgnore] public PermissionNode? Group { get; set; } = null;
|
||||
[JsonIgnore] public PermissionGroup? Group { get; set; } = null;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Value.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class PermissionGroup : ModelBase
|
||||
@ -44,10 +51,9 @@ public class PermissionGroup : ModelBase
|
||||
public class PermissionGroupMember : ModelBase
|
||||
{
|
||||
public Guid GroupId { get; set; }
|
||||
public long AccountId { get; set; }
|
||||
public PermissionGroup Group { get; set; } = null!;
|
||||
public Account.Account Account { get; set; } = null!;
|
||||
|
||||
public Instant? ExpiredAt { get; set; } = null;
|
||||
public Instant? AffectedAt { get; set; } = null;
|
||||
[MaxLength(1024)] public string Actor { get; set; } = null!;
|
||||
|
||||
public Instant? ExpiredAt { get; set; }
|
||||
public Instant? AffectedAt { get; set; }
|
||||
}
|
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 Casbin;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
@ -8,7 +9,7 @@ namespace DysonNetwork.Sphere.Post;
|
||||
|
||||
[ApiController]
|
||||
[Route("/posts")]
|
||||
public class PostController(AppDatabase db, PostService ps, IEnforcer enforcer) : ControllerBase
|
||||
public class PostController(AppDatabase db, PostService ps) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<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]
|
||||
[RequiredPermission("global", "posts.create")]
|
||||
public async Task<ActionResult<Post>> CreatePost(
|
||||
[FromBody] PostRequest request,
|
||||
[FromHeader(Name = "X-Pub")] string? publisherName
|
||||
)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
if (!await enforcer.EnforceAsync((string)HttpContext.Items["CurrentIdentity"]!, "global", "posts", "create"))
|
||||
return StatusCode(403);
|
||||
|
||||
Publisher? publisher;
|
||||
if (publisherName is null)
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Casbin;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -10,7 +11,7 @@ namespace DysonNetwork.Sphere.Post;
|
||||
|
||||
[ApiController]
|
||||
[Route("/publishers")]
|
||||
public class PublisherController(AppDatabase db, PublisherService ps, FileService fs, IEnforcer enforcer)
|
||||
public class PublisherController(AppDatabase db, PublisherService ps, FileService fs)
|
||||
: ControllerBase
|
||||
{
|
||||
[HttpGet("{name}")]
|
||||
@ -167,12 +168,10 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic
|
||||
|
||||
[HttpPost("individual")]
|
||||
[Authorize]
|
||||
[RequiredPermission("global", "publishers.create")]
|
||||
public async Task<ActionResult<Publisher>> CreatePublisherIndividual(PublisherRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
if (!await enforcer.EnforceAsync((string)HttpContext.Items["CurrentIdentity"]!, "global", "publishers",
|
||||
"create"))
|
||||
return StatusCode(403);
|
||||
|
||||
var takenName = request.Name ?? currentUser.Name;
|
||||
var duplicateNameCount = await db.Publishers
|
||||
|
@ -8,6 +8,7 @@ using Casbin.Persist.Adapter.EFCore;
|
||||
using DysonNetwork.Sphere;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Sphere.Auth;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Sphere.Post;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@ -45,22 +46,6 @@ builder.Services.AddControllers().AddJsonOptions(options =>
|
||||
});
|
||||
builder.Services.AddRazorPages();
|
||||
|
||||
// Casbin permissions
|
||||
|
||||
var casbinDbContext = new CasbinDbContext<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
|
||||
|
||||
builder.Services.AddRateLimiter(o => o.AddFixedWindowLimiter(policyName: "fixed", opts =>
|
||||
@ -129,7 +114,10 @@ builder.Services.AddSwaggerGen(options =>
|
||||
});
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
builder.Services.AddScoped<EmailService>();
|
||||
builder.Services.AddScoped<PermissionService>();
|
||||
builder.Services.AddScoped<AccountService>();
|
||||
builder.Services.AddScoped<MagicSpellService>();
|
||||
builder.Services.AddScoped<NotificationService>();
|
||||
builder.Services.AddScoped<AuthService>();
|
||||
builder.Services.AddScoped<FileService>();
|
||||
@ -163,7 +151,7 @@ var app = builder.Build();
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDatabase>();
|
||||
db.Database.Migrate();
|
||||
await db.Database.MigrateAsync();
|
||||
}
|
||||
|
||||
app.MapOpenApi();
|
||||
@ -189,6 +177,7 @@ app.UseRateLimiter();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseAuthorization();
|
||||
app.UseMiddleware<UserInfoMiddleware>();
|
||||
app.UseMiddleware<PermissionMiddleware>();
|
||||
|
||||
app.MapControllers().RequireRateLimiting("fixed");
|
||||
app.MapStaticAssets().RequireRateLimiting("fixed");
|
||||
|
@ -7,8 +7,7 @@
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"App": "Host=localhost;Port=5432;Database=dyson_network;Username=postgres;Password=postgres",
|
||||
"Guard": "Host=localhost;Port=5432;Database=dyson_network_casbin;Username=postgres;Password=postgres"
|
||||
"App": "Host=localhost;Port=5432;Database=dyson_network;Username=postgres;Password=postgres"
|
||||
},
|
||||
"Authentication": {
|
||||
"Schemes": {
|
||||
@ -55,11 +54,20 @@
|
||||
"Production": true,
|
||||
"Google": "path/to/config.json",
|
||||
"Apple": {
|
||||
"PrivateKey": "path/to/cert.p8",
|
||||
"PrivateKey": "path/to/cert.p8",
|
||||
"PrivateKeyId": "",
|
||||
"TeamId": "",
|
||||
"BundleIdentifier": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"Email": {
|
||||
"Server": "",
|
||||
"Port": 465,
|
||||
"Username": "",
|
||||
"Password": "",
|
||||
"FromAddress": "",
|
||||
"FromName": "",
|
||||
"SubjectPrefix": "Solar Network"
|
||||
}
|
||||
}
|
||||
|
@ -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_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_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_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>
|
||||
@ -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_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_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_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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user