:drunk: AI trying to fix bugs
This commit is contained in:
@ -89,6 +89,62 @@ namespace DysonNetwork.Common.Clients
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task DeleteResourceReferencesAsync(string resourceId, string? usage = null)
|
||||
{
|
||||
var url = $"api/filereferences/resource/{resourceId}";
|
||||
if (!string.IsNullOrEmpty(usage))
|
||||
{
|
||||
url += $"?usage={Uri.EscapeDataString(usage)}";
|
||||
}
|
||||
|
||||
var response = await _httpClient.DeleteAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task<List<CloudFileReference>> GetFileReferencesAsync(string fileId)
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"api/filereferences/file/{fileId}");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
await using var stream = await response.Content.ReadAsStreamAsync();
|
||||
var references = await JsonSerializer.DeserializeAsync<List<CloudFileReference>>(stream, _jsonOptions);
|
||||
return references ?? new List<CloudFileReference>();
|
||||
}
|
||||
|
||||
public async Task<List<CloudFileReference>> GetResourceReferencesAsync(string resourceId, string? usage = null)
|
||||
{
|
||||
var url = $"api/filereferences/resource/{resourceId}";
|
||||
if (!string.IsNullOrEmpty(usage))
|
||||
{
|
||||
url += $"?usage={Uri.EscapeDataString(usage)}";
|
||||
}
|
||||
|
||||
var response = await _httpClient.GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
await using var stream = await response.Content.ReadAsStreamAsync();
|
||||
var references = await JsonSerializer.DeserializeAsync<List<CloudFileReference>>(stream, _jsonOptions);
|
||||
return references ?? new List<CloudFileReference>();
|
||||
}
|
||||
|
||||
public async Task<bool> HasReferencesAsync(string fileId)
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"api/filereferences/file/{fileId}/exists");
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
public async Task UpdateReferenceExpirationAsync(string referenceId, Instant? expiredAt)
|
||||
{
|
||||
var request = new { ExpiredAt = expiredAt };
|
||||
var content = new StringContent(
|
||||
JsonSerializer.Serialize(request, _jsonOptions),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
var response = await _httpClient.PutAsync($"api/filereferences/{referenceId}/expiration", content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_httpClient?.Dispose();
|
||||
|
@ -35,24 +35,30 @@ namespace DysonNetwork.Common.Clients
|
||||
return file;
|
||||
}
|
||||
|
||||
public async Task<Stream> DownloadFileAsync(string fileId)
|
||||
public async Task<Stream> GetFileStreamAsync(string fileId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileId))
|
||||
throw new ArgumentNullException(nameof(fileId));
|
||||
|
||||
var response = await _httpClient.GetAsync($"api/files/{fileId}/download");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadAsStreamAsync();
|
||||
var stream = await response.Content.ReadAsStreamAsync();
|
||||
if (stream == null)
|
||||
throw new InvalidOperationException("Failed to read file stream from response.");
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
public async Task<CloudFile> UploadFileAsync(Stream fileStream, string fileName, string contentType, string? folderId = null)
|
||||
public async Task<CloudFile> UploadFileAsync(Stream fileStream, string fileName, string? contentType = null)
|
||||
{
|
||||
using var content = new MultipartFormDataContent();
|
||||
var fileContent = new StreamContent(fileStream);
|
||||
content.Add(fileContent, "file", fileName);
|
||||
|
||||
if (!string.IsNullOrEmpty(folderId))
|
||||
if (!string.IsNullOrEmpty(contentType))
|
||||
{
|
||||
content.Add(new StringContent(folderId), "folderId");
|
||||
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
|
||||
}
|
||||
content.Add(fileContent, "file", fileName);
|
||||
|
||||
var response = await _httpClient.PostAsync("api/files/upload", content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
@ -62,6 +68,39 @@ namespace DysonNetwork.Common.Clients
|
||||
return file;
|
||||
}
|
||||
|
||||
public async Task<CloudFile> ProcessImageAsync(Stream imageStream, string fileName, string? contentType = null)
|
||||
{
|
||||
using var content = new MultipartFormDataContent();
|
||||
var fileContent = new StreamContent(imageStream);
|
||||
if (!string.IsNullOrEmpty(contentType))
|
||||
{
|
||||
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
|
||||
}
|
||||
content.Add(fileContent, "image", fileName);
|
||||
|
||||
var response = await _httpClient.PostAsync("api/files/process-image", content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
await using var responseStream = await response.Content.ReadAsStreamAsync();
|
||||
var file = await JsonSerializer.DeserializeAsync<CloudFile>(responseStream, _jsonOptions);
|
||||
return file;
|
||||
}
|
||||
|
||||
public async Task<string> GetFileUrl(string fileId, bool useCdn = false)
|
||||
{
|
||||
var url = $"api/files/{fileId}/url";
|
||||
if (useCdn)
|
||||
{
|
||||
url += "?useCdn=true";
|
||||
}
|
||||
|
||||
var response = await _httpClient.GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var result = await response.Content.ReadAsStringAsync();
|
||||
return result.Trim('"');
|
||||
}
|
||||
|
||||
public async Task DeleteFileAsync(string fileId)
|
||||
{
|
||||
var response = await _httpClient.DeleteAsync($"api/files/{fileId}");
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
@ -9,7 +9,13 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="EFCore.NamingConventions" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||
<PackageReference Include="NetTopologySuite" Version="2.5.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NodaTime" Version="3.2.2" />
|
||||
|
@ -7,6 +7,15 @@ using OtpNet;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
|
||||
public enum AccountStatus
|
||||
{
|
||||
PendingActivation,
|
||||
Active,
|
||||
Suspended,
|
||||
Banned,
|
||||
Deleted
|
||||
}
|
||||
|
||||
[Index(nameof(Name), IsUnique = true)]
|
||||
public class Account : ModelBase
|
||||
{
|
||||
@ -30,6 +39,47 @@ public class Account : ModelBase
|
||||
[JsonIgnore] public ICollection<Relationship> IncomingRelationships { get; set; } = new List<Relationship>();
|
||||
|
||||
[JsonIgnore] public ICollection<Subscription> Subscriptions { get; set; } = new List<Subscription>();
|
||||
|
||||
public AccountStatus Status { get; set; } = AccountStatus.PendingActivation;
|
||||
|
||||
[NotMapped]
|
||||
public string? Email => GetPrimaryEmail();
|
||||
|
||||
public string? GetPrimaryEmail()
|
||||
{
|
||||
return Contacts
|
||||
.FirstOrDefault(c => c.Type == AccountContactType.Email && c.IsPrimary)
|
||||
?.Content;
|
||||
}
|
||||
|
||||
public void SetPrimaryEmail(string email)
|
||||
{
|
||||
// Remove primary flag from existing primary email if any
|
||||
foreach (var contact in Contacts.Where(c => c.Type == AccountContactType.Email && c.IsPrimary))
|
||||
{
|
||||
contact.IsPrimary = false;
|
||||
}
|
||||
|
||||
// Find or create the email contact
|
||||
var emailContact = Contacts.FirstOrDefault(c =>
|
||||
c.Type == AccountContactType.Email &&
|
||||
string.Equals(c.Content, email, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (emailContact == null)
|
||||
{
|
||||
emailContact = new AccountContact
|
||||
{
|
||||
Type = AccountContactType.Email,
|
||||
Content = email,
|
||||
IsPrimary = true
|
||||
};
|
||||
Contacts.Add(emailContact);
|
||||
}
|
||||
else
|
||||
{
|
||||
emailContact.IsPrimary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Leveling
|
||||
@ -128,12 +178,29 @@ public class AccountAuthFactor : ModelBase
|
||||
/// </summary>
|
||||
public int Trustworthy { get; set; } = 1;
|
||||
|
||||
[MaxLength(100)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
public bool IsDefault { get; set; }
|
||||
public bool IsBackup { get; set; }
|
||||
public Instant? LastUsedAt { get; set; }
|
||||
public Instant? EnabledAt { get; set; }
|
||||
public Instant? ExpiredAt { get; set; }
|
||||
public Instant? DisabledAt { get; set; }
|
||||
|
||||
[Column(TypeName = "jsonb")]
|
||||
public Dictionary<string, object>? Metadata { get; set; }
|
||||
|
||||
public Guid AccountId { get; set; }
|
||||
[JsonIgnore] public Account Account { get; set; } = null!;
|
||||
|
||||
// Navigation property for related AuthSessions
|
||||
[JsonIgnore]
|
||||
public virtual ICollection<AuthSession>? Sessions { get; set; }
|
||||
|
||||
public AccountAuthFactor HashSecret(int cost = 12)
|
||||
{
|
||||
if (Secret == null) return this;
|
||||
@ -174,20 +241,5 @@ public enum AccountAuthFactorType
|
||||
EmailCode,
|
||||
InAppCode,
|
||||
TimedCode,
|
||||
PinCode,
|
||||
}
|
||||
|
||||
public class AccountConnection : ModelBase
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
[MaxLength(4096)] public string Provider { get; set; } = null!;
|
||||
[MaxLength(8192)] public string ProvidedIdentifier { get; set; } = null!;
|
||||
[Column(TypeName = "jsonb")] public Dictionary<string, object>? Meta { get; set; } = new();
|
||||
|
||||
[JsonIgnore] [MaxLength(4096)] public string? AccessToken { get; set; }
|
||||
[JsonIgnore] [MaxLength(4096)] public string? RefreshToken { get; set; }
|
||||
public Instant? LastUsedAt { get; set; }
|
||||
|
||||
public Guid AccountId { get; set; }
|
||||
public Account Account { get; set; } = null!;
|
||||
PinCode
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
@ -8,15 +10,8 @@ namespace DysonNetwork.Common.Models;
|
||||
/// <summary>
|
||||
/// Represents a connection between an account and an authentication provider
|
||||
/// </summary>
|
||||
public class AccountConnection
|
||||
public class AccountConnection : ModelBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique identifier for the connection
|
||||
/// </summary>
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public string Id { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The account ID this connection is associated with
|
||||
/// </summary>
|
||||
@ -36,6 +31,16 @@ public class AccountConnection
|
||||
[MaxLength(256)]
|
||||
public string ProvidedIdentifier { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Alias for ProvidedIdentifier for backward compatibility
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public string ProviderId
|
||||
{
|
||||
get => ProvidedIdentifier;
|
||||
set => ProvidedIdentifier = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display name for the connection
|
||||
/// </summary>
|
||||
@ -57,6 +62,27 @@ public class AccountConnection
|
||||
/// </summary>
|
||||
public Instant? ExpiresAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Raw profile data from the provider
|
||||
/// </summary>
|
||||
[Column(TypeName = "jsonb")]
|
||||
public JsonDocument? ProfileData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the connection was first established
|
||||
/// </summary>
|
||||
public Instant ConnectedAt { get; set; } = SystemClock.Instance.GetCurrentInstant();
|
||||
|
||||
/// <summary>
|
||||
/// Additional metadata about the connection
|
||||
/// </summary>
|
||||
[Column(TypeName = "jsonb")]
|
||||
public JsonDocument? Metadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the connection is currently active
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
/// <summary>
|
||||
/// When the connection was first established
|
||||
/// </summary>
|
||||
@ -67,15 +93,33 @@ public class AccountConnection
|
||||
/// </summary>
|
||||
public Instant? LastUsedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional metadata about the connection
|
||||
/// </summary>
|
||||
[Column(TypeName = "jsonb")]
|
||||
public Dictionary<string, object>? Meta { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for the associated account
|
||||
/// </summary>
|
||||
[ForeignKey(nameof(AccountId))]
|
||||
[JsonIgnore]
|
||||
public virtual Account? Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the connection's tokens and related metadata
|
||||
/// </summary>
|
||||
/// <param name="accessToken">The new access token</param>
|
||||
/// <param name="refreshToken">The new refresh token, if any</param>
|
||||
/// <param name="expiresAt">When the access token expires, if any</param>
|
||||
public void UpdateTokens(string? accessToken, string? refreshToken, Instant? expiresAt)
|
||||
{
|
||||
AccessToken = accessToken;
|
||||
|
||||
if (!string.IsNullOrEmpty(refreshToken))
|
||||
{
|
||||
RefreshToken = refreshToken;
|
||||
}
|
||||
|
||||
if (expiresAt.HasValue)
|
||||
{
|
||||
ExpiresAt = expiresAt;
|
||||
}
|
||||
|
||||
LastUsedAt = SystemClock.Instance.GetCurrentInstant();
|
||||
}
|
||||
}
|
||||
|
47
DysonNetwork.Common/Models/Auth/AuthFactorType.cs
Normal file
47
DysonNetwork.Common/Models/Auth/AuthFactorType.cs
Normal file
@ -0,0 +1,47 @@
|
||||
namespace DysonNetwork.Common.Models.Auth;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the different types of authentication factors that can be used for multi-factor authentication.
|
||||
/// </summary>
|
||||
public enum AuthFactorType
|
||||
{
|
||||
/// <summary>
|
||||
/// Password-based authentication factor.
|
||||
/// </summary>
|
||||
Password = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Time-based One-Time Password (TOTP) authentication factor.
|
||||
/// </summary>
|
||||
Totp = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Email-based authentication factor.
|
||||
/// </summary>
|
||||
Email = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Phone/SMS-based authentication factor.
|
||||
/// </summary>
|
||||
Phone = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Security key (FIDO2/WebAuthn) authentication factor.
|
||||
/// </summary>
|
||||
SecurityKey = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Recovery code authentication factor.
|
||||
/// </summary>
|
||||
RecoveryCode = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Backup code authentication factor.
|
||||
/// </summary>
|
||||
BackupCode = 6,
|
||||
|
||||
/// <summary>
|
||||
/// OpenID Connect (OIDC) authentication factor.
|
||||
/// </summary>
|
||||
Oidc = 7
|
||||
}
|
@ -45,30 +45,3 @@ public enum AuthChallengePlatform
|
||||
System = 100,
|
||||
Unknown = 999
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum AuthFactorType
|
||||
{
|
||||
Password = 0,
|
||||
EmailCode = 1,
|
||||
PhoneCode = 2,
|
||||
Totp = 3,
|
||||
WebAuthn = 4,
|
||||
RecoveryCode = 5,
|
||||
|
||||
// Social and federation
|
||||
Google = 10,
|
||||
Apple = 11,
|
||||
Microsoft = 12,
|
||||
Facebook = 13,
|
||||
Twitter = 14,
|
||||
Github = 15,
|
||||
|
||||
// Enterprise
|
||||
Saml = 50,
|
||||
Oidc = 51,
|
||||
Ldap = 52,
|
||||
|
||||
// Custom factor types
|
||||
Custom = 100
|
||||
}
|
||||
|
@ -1,10 +1,33 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all entity models in the system.
|
||||
/// Provides common properties and functionality for tracking entity lifecycle.
|
||||
/// </summary>
|
||||
public abstract class ModelBase
|
||||
{
|
||||
public Instant CreatedAt { get; set; }
|
||||
public Instant UpdatedAt { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier for the entity.
|
||||
/// </summary>
|
||||
[Key]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time when the entity was created, in UTC.
|
||||
/// </summary>
|
||||
public Instant CreatedAt { get; set; } = SystemClock.Instance.GetCurrentInstant();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time when the entity was last updated, in UTC.
|
||||
/// </summary>
|
||||
public Instant UpdatedAt { get; set; } = SystemClock.Instance.GetCurrentInstant();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time when the entity was soft-deleted, in UTC.
|
||||
/// Null if the entity has not been deleted.
|
||||
/// </summary>
|
||||
public Instant? DeletedAt { get; set; }
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace DysonNetwork.Common.Models;
|
||||
|
||||
|
100
DysonNetwork.Common/Services/Permission/PermissionMiddleware.cs
Normal file
100
DysonNetwork.Common/Services/Permission/PermissionMiddleware.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using DysonNetwork.Common.Extensions;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
|
||||
namespace DysonNetwork.Common.Services.Permission;
|
||||
|
||||
[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<TDbContext> where TDbContext : DbContext
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public PermissionMiddleware(RequestDelegate next, IServiceProvider serviceProvider)
|
||||
{
|
||||
_next = next;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext httpContext)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var permissionService = new PermissionService<TDbContext>(
|
||||
scope.ServiceProvider.GetRequiredService<TDbContext>(),
|
||||
scope.ServiceProvider.GetRequiredService<ICacheService>()
|
||||
);
|
||||
|
||||
var endpoint = httpContext.GetEndpoint();
|
||||
var attr = endpoint?.Metadata.OfType<RequiredPermissionAttribute>().FirstOrDefault();
|
||||
|
||||
if (attr != null)
|
||||
{
|
||||
if (httpContext.User.Identity?.IsAuthenticated != true)
|
||||
{
|
||||
httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
await httpContext.Response.WriteAsync("Unauthorized");
|
||||
return;
|
||||
}
|
||||
|
||||
var currentUserId = httpContext.User.GetUserId();
|
||||
if (currentUserId == Guid.Empty)
|
||||
{
|
||||
httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
await httpContext.Response.WriteAsync("Unauthorized");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Check for superuser from PassClient
|
||||
// if (currentUser.IsSuperuser)
|
||||
// {
|
||||
// await _next(httpContext);
|
||||
// return;
|
||||
// }
|
||||
|
||||
var actor = $"user:{currentUserId}";
|
||||
var hasPermission = await permissionService.HasPermissionAsync(actor, attr.Area, attr.Key);
|
||||
|
||||
if (!hasPermission)
|
||||
{
|
||||
httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
await httpContext.Response.WriteAsync("Forbidden");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await _next.Invoke(httpContext);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PermissionServiceExtensions
|
||||
{
|
||||
public static IServiceCollection AddPermissionService<TDbContext>(this IServiceCollection services)
|
||||
where TDbContext : DbContext
|
||||
{
|
||||
services.AddScoped<PermissionService<TDbContext>>(sp =>
|
||||
new PermissionService<TDbContext>(
|
||||
sp.GetRequiredService<TDbContext>(),
|
||||
sp.GetRequiredService<ICacheService>()
|
||||
));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UsePermissionMiddleware<TDbContext>(this IApplicationBuilder builder)
|
||||
where TDbContext : DbContext
|
||||
{
|
||||
return builder.UseMiddleware<PermissionMiddleware<TDbContext>>(builder.ApplicationServices);
|
||||
}
|
||||
}
|
203
DysonNetwork.Common/Services/Permission/PermissionService.cs
Normal file
203
DysonNetwork.Common/Services/Permission/PermissionService.cs
Normal file
@ -0,0 +1,203 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Common.Services;
|
||||
|
||||
namespace DysonNetwork.Common.Services.Permission;
|
||||
|
||||
public class PermissionService<TDbContext> where TDbContext : DbContext
|
||||
{
|
||||
private readonly TDbContext _db;
|
||||
private readonly ICacheService _cache;
|
||||
private static readonly TimeSpan CacheExpiration = TimeSpan.FromMinutes(1);
|
||||
|
||||
private const string PermCacheKeyPrefix = "perm:";
|
||||
private const string PermGroupCacheKeyPrefix = "perm-cg:";
|
||||
private const string PermissionGroupPrefix = "perm-g:";
|
||||
|
||||
public PermissionService(TDbContext db, ICacheService cache)
|
||||
{
|
||||
_db = db;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
private static string GetPermissionCacheKey(string actor, string area, string key) =>
|
||||
PermCacheKeyPrefix + actor + ":" + area + ":" + key;
|
||||
|
||||
private static string GetGroupsCacheKey(string actor) =>
|
||||
PermGroupCacheKeyPrefix + actor;
|
||||
|
||||
private static string GetPermissionGroupKey(string actor) =>
|
||||
PermissionGroupPrefix + actor;
|
||||
|
||||
public async Task<bool> HasPermissionAsync(string actor, string area, string key)
|
||||
{
|
||||
var value = await GetPermissionAsync<bool>(actor, area, key);
|
||||
return value;
|
||||
}
|
||||
|
||||
public async Task<T?> GetPermissionAsync<T>(string actor, string area, string key)
|
||||
{
|
||||
var cacheKey = GetPermissionCacheKey(actor, area, key);
|
||||
|
||||
var (hit, cachedValue) = await _cache.GetAsyncWithStatus<T>(cacheKey);
|
||||
if (hit)
|
||||
return cachedValue;
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var groupsKey = GetGroupsCacheKey(actor);
|
||||
|
||||
var groupsId = await _cache.GetAsync<List<Guid>>(groupsKey);
|
||||
if (groupsId == null)
|
||||
{
|
||||
groupsId = await _db.Set<PermissionGroupMember>()
|
||||
.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();
|
||||
|
||||
await _cache.SetWithGroupsAsync(groupsKey, groupsId,
|
||||
[GetPermissionGroupKey(actor)],
|
||||
CacheExpiration);
|
||||
}
|
||||
|
||||
var permission = await _db.Set<PermissionNode>()
|
||||
.Where(n => (n.GroupId == null && n.Actor == actor) ||
|
||||
(n.GroupId != null && groupsId.Contains(n.GroupId.Value)))
|
||||
.Where(n => n.Key == key && n.Area == area)
|
||||
.Where(n => n.ExpiredAt == null || n.ExpiredAt > now)
|
||||
.Where(n => n.AffectedAt == null || n.AffectedAt <= now)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
var result = permission is not null ? DeserializePermissionValue<T>(permission.Value) : default;
|
||||
|
||||
await _cache.SetWithGroupsAsync(cacheKey, result,
|
||||
[GetPermissionGroupKey(actor)],
|
||||
CacheExpiration);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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.Set<PermissionNode>().Add(node);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// Invalidate related caches
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
|
||||
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.Set<PermissionNode>().Add(node);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// Invalidate related caches
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
await _cache.RemoveAsync(GetGroupsCacheKey(actor));
|
||||
await _cache.RemoveGroupAsync(GetPermissionGroupKey(actor));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public async Task RemovePermissionNode(string actor, string area, string key)
|
||||
{
|
||||
var node = await _db.Set<PermissionNode>()
|
||||
.Where(n => n.Actor == actor && n.Area == area && n.Key == key)
|
||||
.FirstOrDefaultAsync();
|
||||
if (node is not null) _db.Set<PermissionNode>().Remove(node);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// Invalidate cache
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
}
|
||||
|
||||
public async Task RemovePermissionNodeFromGroup(PermissionGroup group, string actor, string area, string key)
|
||||
{
|
||||
var node = await _db.Set<PermissionNode>()
|
||||
.Where(n => n.GroupId == group.Id)
|
||||
.Where(n => n.Actor == actor && n.Area == area && n.Key == key)
|
||||
.FirstOrDefaultAsync();
|
||||
if (node is null) return;
|
||||
_db.Set<PermissionNode>().Remove(node);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// Invalidate caches
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
await _cache.RemoveAsync(GetGroupsCacheKey(actor));
|
||||
await _cache.RemoveGroupAsync(GetPermissionGroupKey(actor));
|
||||
}
|
||||
|
||||
private async Task InvalidatePermissionCacheAsync(string actor, string area, string key)
|
||||
{
|
||||
var cacheKey = GetPermissionCacheKey(actor, area, key);
|
||||
await _cache.RemoveAsync(cacheKey);
|
||||
}
|
||||
|
||||
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),
|
||||
};
|
||||
}
|
||||
}
|
@ -2,14 +2,14 @@ using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Pass.Features.Auth.Models;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
// Permission types are now in DysonNetwork.Common.Models
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using NodaTime;
|
||||
using Quartz;
|
||||
using Account = DysonNetwork.Pass.Features.Auth.Models.Account;
|
||||
using AccountConnection = DysonNetwork.Pass.Features.Auth.Models.AccountConnection;
|
||||
using AccountAuthFactor = DysonNetwork.Pass.Features.Auth.Models.AccountAuthFactor;
|
||||
using Account = DysonNetwork.Common.Models.Account;
|
||||
using AccountConnection = DysonNetwork.Common.Models.AccountConnection;
|
||||
using AccountAuthFactor = DysonNetwork.Common.Models.AccountAuthFactor;
|
||||
using AuthSession = DysonNetwork.Pass.Features.Auth.Models.AuthSession;
|
||||
using AuthChallenge = DysonNetwork.Pass.Features.Auth.Models.AuthChallenge;
|
||||
|
||||
|
@ -44,7 +44,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DysonNetwork.Common\DysonNetwork.Common.csproj" />
|
||||
<ProjectReference Include="..\DysonNetwork.Sphere\DysonNetwork.Sphere.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -212,7 +212,7 @@ public class AccountCurrentController(
|
||||
}
|
||||
|
||||
[HttpPost("statuses")]
|
||||
[DysonNetwork.Sphere.Permission.RequiredPermission("global", "accounts.statuses.create")]
|
||||
[DysonNetwork.Common.Services.Permission.RequiredPermission("global", "accounts.statuses.create")]
|
||||
public async Task<ActionResult<Status>> CreateStatus([FromBody] AccountController.StatusRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
@ -140,7 +140,7 @@ public class NotificationController(PassDatabase db, NotificationService nty) :
|
||||
|
||||
[HttpPost("send")]
|
||||
[Authorize]
|
||||
[DysonNetwork.Sphere.Permission.RequiredPermission("global", "notifications.send")]
|
||||
[DysonNetwork.Common.Services.Permission.RequiredPermission("global", "notifications.send")]
|
||||
public async Task<ActionResult> SendNotification(
|
||||
[FromBody] NotificationWithAimRequest request,
|
||||
[FromQuery] bool save = false
|
||||
|
@ -3,7 +3,7 @@ using DysonNetwork.Pass.Features.Auth;
|
||||
using DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
using DysonNetwork.Pass.Email;
|
||||
using DysonNetwork.Pass.Localization;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
// Permission types are now in DysonNetwork.Common.Models
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using EFCore.BulkExtensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -3,7 +3,7 @@ using DysonNetwork.Pass.Storage;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
// Permission types are now in DysonNetwork.Common.Models
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Account;
|
||||
|
||||
|
@ -6,7 +6,7 @@ namespace DysonNetwork.Pass.Features.Auth.Interfaces;
|
||||
public interface IOidcService
|
||||
{
|
||||
string GetAuthorizationUrl(string state, string nonce);
|
||||
Task<OidcUserInfo> ProcessCallbackAsync(OidcCallbackData callbackData);
|
||||
Task<DysonNetwork.Common.Models.OidcUserInfo> ProcessCallbackAsync(OidcCallbackData callbackData);
|
||||
Task<AuthResult> AuthenticateAsync(string provider, string code, string state);
|
||||
IEnumerable<string> GetSupportedProviders();
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
using DysonNetwork.Common.Models;
|
||||
using NodaTime;
|
||||
using AccountConnection = DysonNetwork.Common.Models.AccountConnection;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.Models;
|
||||
|
||||
|
@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Common.Models.Auth;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.Models;
|
||||
@ -34,6 +35,9 @@ public class AccountAuthFactor : ModelBase
|
||||
[Required]
|
||||
public bool IsBackup { get; set; }
|
||||
|
||||
[Required]
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
public Instant? LastUsedAt { get; set; }
|
||||
|
||||
public Instant? EnabledAt { get; set; }
|
||||
|
@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using DysonNetwork.Pass.Models;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.Models;
|
||||
|
||||
public class AccountConnection : ModelBase
|
||||
{
|
||||
[Required]
|
||||
public Guid AccountId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(AccountId))]
|
||||
[JsonIgnore]
|
||||
public virtual Account Account { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[MaxLength(256)]
|
||||
public string ProviderId { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(256)]
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
[MaxLength(1000)]
|
||||
public string? AccessToken { get; set; }
|
||||
|
||||
[MaxLength(1000)]
|
||||
public string? RefreshToken { get; set; }
|
||||
|
||||
public Instant? ExpiresAt { get; set; }
|
||||
|
||||
[Column(TypeName = "jsonb")]
|
||||
public JsonDocument? ProfileData { get; set; }
|
||||
|
||||
public Instant ConnectedAt { get; set; } = SystemClock.Instance.GetCurrentInstant();
|
||||
public Instant? LastUsedAt { get; set; }
|
||||
|
||||
[Column(TypeName = "jsonb")]
|
||||
public JsonDocument? Metadata { get; set; }
|
||||
|
||||
public bool IsConnected => ExpiresAt == null || ExpiresAt > SystemClock.Instance.GetCurrentInstant();
|
||||
|
||||
public void UpdateTokens(string? accessToken, string? refreshToken, Instant? expiresAt)
|
||||
{
|
||||
AccessToken = accessToken;
|
||||
RefreshToken = refreshToken;
|
||||
ExpiresAt = expiresAt;
|
||||
LastUsedAt = SystemClock.Instance.GetCurrentInstant();
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
AccessToken = null;
|
||||
RefreshToken = null;
|
||||
ExpiresAt = null;
|
||||
ConnectedAt = default; // Set to default value for Instant
|
||||
}
|
||||
|
||||
public void UpdateProfileData(JsonDocument? profileData)
|
||||
{
|
||||
ProfileData = profileData;
|
||||
}
|
||||
}
|
@ -6,6 +6,8 @@ using DysonNetwork.Pass.Storage;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Common.Models;
|
||||
using Account = DysonNetwork.Common.Models.Account;
|
||||
using AccountConnection = DysonNetwork.Common.Models.AccountConnection;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
@ -27,21 +29,24 @@ public class ConnectionController(
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<AccountConnection>>> GetConnections()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Models.Account currentUser)
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser)
|
||||
return Unauthorized();
|
||||
|
||||
var connections = await db.AccountConnections
|
||||
.Where(c => c.AccountId == currentUser.Id)
|
||||
.Select(c => new
|
||||
.Select(c => new AccountConnection
|
||||
{
|
||||
c.Id,
|
||||
c.AccountId,
|
||||
c.Provider,
|
||||
c.ProvidedIdentifier,
|
||||
c.Meta,
|
||||
c.LastUsedAt,
|
||||
c.CreatedAt,
|
||||
c.UpdatedAt,
|
||||
Id = c.Id,
|
||||
AccountId = c.AccountId,
|
||||
Provider = c.Provider,
|
||||
ProvidedIdentifier = c.ProvidedIdentifier,
|
||||
DisplayName = c.DisplayName,
|
||||
AccessToken = c.AccessToken,
|
||||
RefreshToken = c.RefreshToken,
|
||||
ExpiresAt = c.ExpiresAt,
|
||||
LastUsedAt = c.LastUsedAt,
|
||||
CreatedAt = c.CreatedAt,
|
||||
UpdatedAt = c.UpdatedAt
|
||||
})
|
||||
.ToListAsync();
|
||||
return Ok(connections);
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Common.Services;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
@ -47,7 +47,7 @@ public class DiscordOidcService(
|
||||
})!;
|
||||
}
|
||||
|
||||
public override async Task<OidcUserInfo> ProcessCallbackAsync(OidcCallbackData callbackData)
|
||||
public override async Task<DysonNetwork.Common.Models.OidcUserInfo> ProcessCallbackAsync(OidcCallbackData callbackData)
|
||||
{
|
||||
var tokenResponse = await ExchangeCodeForTokensAsync(callbackData.Code);
|
||||
if (tokenResponse?.AccessToken == null)
|
||||
@ -84,7 +84,7 @@ public class DiscordOidcService(
|
||||
return await response.Content.ReadFromJsonAsync<OidcTokenResponse>();
|
||||
}
|
||||
|
||||
private async Task<OidcUserInfo> GetUserInfoAsync(string accessToken)
|
||||
private async Task<DysonNetwork.Common.Models.OidcUserInfo> GetUserInfoAsync(string accessToken)
|
||||
{
|
||||
var client = HttpClientFactory.CreateClient();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "https://discord.com/users/@me");
|
||||
@ -99,7 +99,7 @@ public class DiscordOidcService(
|
||||
var userId = discordUser.GetProperty("id").GetString() ?? "";
|
||||
var avatar = discordUser.TryGetProperty("avatar", out var avatarElement) ? avatarElement.GetString() : null;
|
||||
|
||||
return new OidcUserInfo
|
||||
return new DysonNetwork.Common.Models.OidcUserInfo
|
||||
{
|
||||
UserId = userId,
|
||||
Email = (discordUser.TryGetProperty("email", out var emailElement) ? emailElement.GetString() : null) ?? "",
|
||||
|
@ -1,6 +1,8 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Common.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
@ -48,7 +50,7 @@ public abstract class OidcService(
|
||||
/// <summary>
|
||||
/// Process the callback from the OIDC provider
|
||||
/// </summary>
|
||||
public abstract Task<OidcUserInfo> ProcessCallbackAsync(OidcCallbackData callbackData);
|
||||
public abstract Task<DysonNetwork.Common.Models.OidcUserInfo> ProcessCallbackAsync(OidcCallbackData callbackData);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the provider configuration
|
||||
@ -145,7 +147,7 @@ public abstract class OidcService(
|
||||
/// <summary>
|
||||
/// Validates and extracts information from an ID token
|
||||
/// </summary>
|
||||
protected virtual OidcUserInfo ValidateAndExtractIdToken(string idToken,
|
||||
protected virtual DysonNetwork.Common.Models.OidcUserInfo ValidateAndExtractIdToken(string idToken,
|
||||
TokenValidationParameters validationParameters)
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
@ -171,18 +173,24 @@ public abstract class OidcService(
|
||||
username = !string.IsNullOrEmpty(email) ? email.Split('@')[0] : null;
|
||||
}
|
||||
|
||||
return new OidcUserInfo
|
||||
// Convert the user info to our model
|
||||
var userInfo = new DysonNetwork.Common.Models.OidcUserInfo
|
||||
{
|
||||
UserId = userId,
|
||||
Email = email,
|
||||
EmailVerified = emailVerified,
|
||||
FirstName = givenName ?? "",
|
||||
LastName = familyName ?? "",
|
||||
DisplayName = name ?? $"{givenName} {familyName}".Trim(),
|
||||
PreferredUsername = username ?? "",
|
||||
ProfilePictureUrl = picture,
|
||||
Provider = ProviderName
|
||||
GivenName = givenName,
|
||||
FamilyName = familyName,
|
||||
Name = name,
|
||||
UserId = userId,
|
||||
Picture = picture,
|
||||
AccessToken = "",
|
||||
RefreshToken = "",
|
||||
Provider = ProviderName,
|
||||
ExpiresAt = null,
|
||||
Claims = null
|
||||
};
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -190,7 +198,7 @@ public abstract class OidcService(
|
||||
/// Also creates or updates the account connection
|
||||
/// </summary>
|
||||
public async Task<Challenge> CreateChallengeForUserAsync(
|
||||
OidcUserInfo userInfo,
|
||||
DysonNetwork.Common.Models.OidcUserInfo userInfo,
|
||||
Models.Account account,
|
||||
HttpContext request,
|
||||
string deviceId
|
||||
@ -205,14 +213,16 @@ public abstract class OidcService(
|
||||
|
||||
if (connection is null)
|
||||
{
|
||||
connection = new AccountConnection
|
||||
connection = new DysonNetwork.Common.Models.AccountConnection
|
||||
{
|
||||
Provider = ProviderName,
|
||||
ProvidedIdentifier = userInfo.UserId ?? "",
|
||||
AccessToken = userInfo.AccessToken,
|
||||
RefreshToken = userInfo.RefreshToken,
|
||||
LastUsedAt = SystemClock.Instance.GetCurrentInstant(),
|
||||
AccountId = account.Id
|
||||
AccountId = account.Id,
|
||||
CreatedAt = SystemClock.Instance.GetCurrentInstant(),
|
||||
ProfileData = userInfo.Claims != null ? JsonSerializer.SerializeToDocument(userInfo.Claims) : null
|
||||
};
|
||||
await Db.AccountConnections.AddAsync(connection);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.RegularExpressions;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Common.Services.Permission;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Common.Interfaces;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Sphere.Localization;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Common.Services.Permission;
|
||||
using DysonNetwork.Sphere.Realm;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
@ -1,4 +1,4 @@
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Common.Services.Permission;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,182 +0,0 @@
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Sphere.Developer;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class CustomAppsRefine : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "allow_offline_access",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "allowed_grant_types",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "allowed_scopes",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "client_uri",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "logo_uri",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "post_logout_redirect_uris",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "redirect_uris",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "require_pkce",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "verified_at",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "verified_as",
|
||||
table: "custom_apps",
|
||||
newName: "description");
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "background",
|
||||
table: "custom_apps",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<CustomAppLinks>(
|
||||
name: "links",
|
||||
table: "custom_apps",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<CustomAppOauthConfig>(
|
||||
name: "oauth_config",
|
||||
table: "custom_apps",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "picture",
|
||||
table: "custom_apps",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<VerificationMark>(
|
||||
name: "verification",
|
||||
table: "custom_apps",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "background",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "links",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "oauth_config",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "picture",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "verification",
|
||||
table: "custom_apps");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "description",
|
||||
table: "custom_apps",
|
||||
newName: "verified_as");
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "allow_offline_access",
|
||||
table: "custom_apps",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "allowed_grant_types",
|
||||
table: "custom_apps",
|
||||
type: "character varying(256)",
|
||||
maxLength: 256,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "allowed_scopes",
|
||||
table: "custom_apps",
|
||||
type: "character varying(256)",
|
||||
maxLength: 256,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "client_uri",
|
||||
table: "custom_apps",
|
||||
type: "character varying(1024)",
|
||||
maxLength: 1024,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "logo_uri",
|
||||
table: "custom_apps",
|
||||
type: "character varying(4096)",
|
||||
maxLength: 4096,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "post_logout_redirect_uris",
|
||||
table: "custom_apps",
|
||||
type: "character varying(4096)",
|
||||
maxLength: 4096,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "redirect_uris",
|
||||
table: "custom_apps",
|
||||
type: "character varying(4096)",
|
||||
maxLength: 4096,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "require_pkce",
|
||||
table: "custom_apps",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "verified_at",
|
||||
table: "custom_apps",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Common.Services.Permission;
|
||||
using DysonNetwork.Sphere.Publisher;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -16,6 +16,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DysonNetwork.Common\DysonNetwork.Common.csproj" />
|
||||
<ProjectReference Include="..\DysonNetwork.Pass\DysonNetwork.Pass.csproj" />
|
||||
|
||||
<PackageReference Include="AngleSharp" Version="1.3.0" />
|
||||
|
||||
<PackageReference Include="BlurHashSharp.SkiaSharp" Version="1.3.4" />
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,61 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class EnrichAccountProfile : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "birthday",
|
||||
table: "account_profiles",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "gender",
|
||||
table: "account_profiles",
|
||||
type: "character varying(1024)",
|
||||
maxLength: 1024,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "last_seen_at",
|
||||
table: "account_profiles",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "pronouns",
|
||||
table: "account_profiles",
|
||||
type: "character varying(1024)",
|
||||
maxLength: 1024,
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "birthday",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "gender",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "last_seen_at",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "pronouns",
|
||||
table: "account_profiles");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,52 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FixProfileRelationship : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_account_profiles_accounts_id",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_account_profiles_account_id",
|
||||
table: "account_profiles",
|
||||
column: "account_id",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_account_profiles_accounts_account_id",
|
||||
table: "account_profiles",
|
||||
column: "account_id",
|
||||
principalTable: "accounts",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_account_profiles_accounts_account_id",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_account_profiles_account_id",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_account_profiles_accounts_id",
|
||||
table: "account_profiles",
|
||||
column: "id",
|
||||
principalTable: "accounts",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,89 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RefactorChatLastRead : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "chat_read_receipts");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "type",
|
||||
table: "chat_messages",
|
||||
type: "character varying(1024)",
|
||||
maxLength: 1024,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "last_read_at",
|
||||
table: "chat_members",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "last_read_at",
|
||||
table: "chat_members");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "type",
|
||||
table: "chat_messages",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(1024)",
|
||||
oldMaxLength: 1024);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "chat_read_receipts",
|
||||
columns: table => new
|
||||
{
|
||||
message_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
sender_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_chat_read_receipts", x => new { x.message_id, x.sender_id });
|
||||
table.ForeignKey(
|
||||
name: "fk_chat_read_receipts_chat_members_sender_id",
|
||||
column: x => x.sender_id,
|
||||
principalTable: "chat_members",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "fk_chat_read_receipts_chat_messages_message_id",
|
||||
column: x => x.message_id,
|
||||
principalTable: "chat_messages",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_chat_read_receipts_message_id_sender_id",
|
||||
table: "chat_read_receipts",
|
||||
columns: new[] { "message_id", "sender_id" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_chat_read_receipts_sender_id",
|
||||
table: "chat_read_receipts",
|
||||
column: "sender_id");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,78 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class UpdateRealtimeChat : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_notification_push_subscriptions_device_id",
|
||||
table: "notification_push_subscriptions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_notification_push_subscriptions_device_token",
|
||||
table: "notification_push_subscriptions");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "title",
|
||||
table: "chat_realtime_call",
|
||||
newName: "session_id");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "provider_name",
|
||||
table: "chat_realtime_call",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "upstream",
|
||||
table: "chat_realtime_call",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_notification_push_subscriptions_device_token_device_id",
|
||||
table: "notification_push_subscriptions",
|
||||
columns: new[] { "device_token", "device_id" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_notification_push_subscriptions_device_token_device_id",
|
||||
table: "notification_push_subscriptions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "provider_name",
|
||||
table: "chat_realtime_call");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "upstream",
|
||||
table: "chat_realtime_call");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "session_id",
|
||||
table: "chat_realtime_call",
|
||||
newName: "title");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_notification_push_subscriptions_device_id",
|
||||
table: "notification_push_subscriptions",
|
||||
column: "device_id",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_notification_push_subscriptions_device_token",
|
||||
table: "notification_push_subscriptions",
|
||||
column: "device_token",
|
||||
unique: true);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,34 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ModifyRelationshipStatusType : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<short>(
|
||||
name: "status",
|
||||
table: "account_relationships",
|
||||
type: "smallint",
|
||||
nullable: false,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "status",
|
||||
table: "account_relationships",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
oldClrType: typeof(short),
|
||||
oldType: "smallint");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class LimitedSizeForPictureIdOnPub : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddCloudFileUsage : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "usage",
|
||||
table: "files",
|
||||
type: "character varying(1024)",
|
||||
maxLength: 1024,
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "usage",
|
||||
table: "files");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,436 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RefactorCloudFileReference : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_account_profiles_files_background_id",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_account_profiles_files_picture_id",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_chat_rooms_files_background_id",
|
||||
table: "chat_rooms");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_chat_rooms_files_picture_id",
|
||||
table: "chat_rooms");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_posts_posts_threaded_post_id",
|
||||
table: "posts");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_publishers_files_background_id",
|
||||
table: "publishers");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_publishers_files_picture_id",
|
||||
table: "publishers");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_realms_files_background_id",
|
||||
table: "realms");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_realms_files_picture_id",
|
||||
table: "realms");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_stickers_files_image_id",
|
||||
table: "stickers");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_stickers_image_id",
|
||||
table: "stickers");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_realms_background_id",
|
||||
table: "realms");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_realms_picture_id",
|
||||
table: "realms");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_publishers_background_id",
|
||||
table: "publishers");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_publishers_picture_id",
|
||||
table: "publishers");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_posts_threaded_post_id",
|
||||
table: "posts");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_chat_rooms_background_id",
|
||||
table: "chat_rooms");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_chat_rooms_picture_id",
|
||||
table: "chat_rooms");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_account_profiles_background_id",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_account_profiles_picture_id",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "threaded_post_id",
|
||||
table: "posts");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "expired_at",
|
||||
table: "files");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "usage",
|
||||
table: "files");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "used_count",
|
||||
table: "files");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "image_id",
|
||||
table: "stickers",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(32)",
|
||||
oldMaxLength: 32);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "image",
|
||||
table: "stickers",
|
||||
type: "jsonb",
|
||||
nullable: true,
|
||||
defaultValueSql: "'[]'::jsonb"
|
||||
);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "background",
|
||||
table: "realms",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "picture",
|
||||
table: "realms",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "background",
|
||||
table: "publishers",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "picture",
|
||||
table: "publishers",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<List<CloudFileReferenceObject>>(
|
||||
name: "attachments",
|
||||
table: "posts",
|
||||
type: "jsonb",
|
||||
nullable: false,
|
||||
defaultValueSql: "'[]'::jsonb"
|
||||
);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "background",
|
||||
table: "chat_rooms",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "picture",
|
||||
table: "chat_rooms",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<List<CloudFileReferenceObject>>(
|
||||
name: "attachments",
|
||||
table: "chat_messages",
|
||||
type: "jsonb",
|
||||
nullable: false,
|
||||
defaultValueSql: "'[]'::jsonb"
|
||||
);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "background",
|
||||
table: "account_profiles",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<CloudFileReferenceObject>(
|
||||
name: "picture",
|
||||
table: "account_profiles",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "file_references",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
file_id = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
usage = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||
resource_id = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_file_references", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_file_references_files_file_id",
|
||||
column: x => x.file_id,
|
||||
principalTable: "files",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_file_references_file_id",
|
||||
table: "file_references",
|
||||
column: "file_id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "file_references");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "image",
|
||||
table: "stickers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "background",
|
||||
table: "realms");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "picture",
|
||||
table: "realms");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "background",
|
||||
table: "publishers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "picture",
|
||||
table: "publishers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "attachments",
|
||||
table: "posts");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "background",
|
||||
table: "chat_rooms");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "picture",
|
||||
table: "chat_rooms");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "attachments",
|
||||
table: "chat_messages");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "background",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "picture",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "image_id",
|
||||
table: "stickers",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(32)",
|
||||
oldMaxLength: 32,
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "threaded_post_id",
|
||||
table: "posts",
|
||||
type: "uuid",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "expired_at",
|
||||
table: "files",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "usage",
|
||||
table: "files",
|
||||
type: "character varying(1024)",
|
||||
maxLength: 1024,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "used_count",
|
||||
table: "files",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_stickers_image_id",
|
||||
table: "stickers",
|
||||
column: "image_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_realms_background_id",
|
||||
table: "realms",
|
||||
column: "background_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_realms_picture_id",
|
||||
table: "realms",
|
||||
column: "picture_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_publishers_background_id",
|
||||
table: "publishers",
|
||||
column: "background_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_publishers_picture_id",
|
||||
table: "publishers",
|
||||
column: "picture_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_posts_threaded_post_id",
|
||||
table: "posts",
|
||||
column: "threaded_post_id",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_chat_rooms_background_id",
|
||||
table: "chat_rooms",
|
||||
column: "background_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_chat_rooms_picture_id",
|
||||
table: "chat_rooms",
|
||||
column: "picture_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_account_profiles_background_id",
|
||||
table: "account_profiles",
|
||||
column: "background_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_account_profiles_picture_id",
|
||||
table: "account_profiles",
|
||||
column: "picture_id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_account_profiles_files_background_id",
|
||||
table: "account_profiles",
|
||||
column: "background_id",
|
||||
principalTable: "files",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_account_profiles_files_picture_id",
|
||||
table: "account_profiles",
|
||||
column: "picture_id",
|
||||
principalTable: "files",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_chat_rooms_files_background_id",
|
||||
table: "chat_rooms",
|
||||
column: "background_id",
|
||||
principalTable: "files",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_chat_rooms_files_picture_id",
|
||||
table: "chat_rooms",
|
||||
column: "picture_id",
|
||||
principalTable: "files",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_posts_posts_threaded_post_id",
|
||||
table: "posts",
|
||||
column: "threaded_post_id",
|
||||
principalTable: "posts",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_publishers_files_background_id",
|
||||
table: "publishers",
|
||||
column: "background_id",
|
||||
principalTable: "files",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_publishers_files_picture_id",
|
||||
table: "publishers",
|
||||
column: "picture_id",
|
||||
principalTable: "files",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_realms_files_background_id",
|
||||
table: "realms",
|
||||
column: "background_id",
|
||||
principalTable: "files",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_realms_files_picture_id",
|
||||
table: "realms",
|
||||
column: "picture_id",
|
||||
principalTable: "files",
|
||||
principalColumn: "id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_stickers_files_image_id",
|
||||
table: "stickers",
|
||||
column: "image_id",
|
||||
principalTable: "files",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,38 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FixPushNotificationIndex : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_notification_push_subscriptions_device_token_device_id",
|
||||
table: "notification_push_subscriptions");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_notification_push_subscriptions_device_token_device_id_acco",
|
||||
table: "notification_push_subscriptions",
|
||||
columns: new[] { "device_token", "device_id", "account_id" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_notification_push_subscriptions_device_token_device_id_acco",
|
||||
table: "notification_push_subscriptions");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_notification_push_subscriptions_device_token_device_id",
|
||||
table: "notification_push_subscriptions",
|
||||
columns: new[] { "device_token", "device_id" },
|
||||
unique: true);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RemoveActivities : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "activities");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "activities",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
account_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||
meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: false),
|
||||
resource_identifier = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
||||
type = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||
users_visible = table.Column<ICollection<Guid>>(type: "jsonb", nullable: false),
|
||||
visibility = table.Column<int>(type: "integer", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_activities", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_activities_accounts_account_id",
|
||||
column: x => x.account_id,
|
||||
principalTable: "accounts",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_activities_account_id",
|
||||
table: "activities",
|
||||
column: "account_id");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Sphere.Chat;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class EnrichChatMembers : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "break_until",
|
||||
table: "chat_members",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<ChatTimeoutCause>(
|
||||
name: "timeout_cause",
|
||||
table: "chat_members",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "timeout_until",
|
||||
table: "chat_members",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "break_until",
|
||||
table: "chat_members");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "timeout_cause",
|
||||
table: "chat_members");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "timeout_until",
|
||||
table: "chat_members");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,91 +0,0 @@
|
||||
using DysonNetwork.Common.Models;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ActiveBadgeAndVerification : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "verified_as",
|
||||
table: "realms");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "verified_at",
|
||||
table: "realms");
|
||||
|
||||
migrationBuilder.AddColumn<VerificationMark>(
|
||||
name: "verification",
|
||||
table: "realms",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<VerificationMark>(
|
||||
name: "verification",
|
||||
table: "publishers",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "activated_at",
|
||||
table: "badges",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<BadgeReferenceObject>(
|
||||
name: "active_badge",
|
||||
table: "account_profiles",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<VerificationMark>(
|
||||
name: "verification",
|
||||
table: "account_profiles",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "verification",
|
||||
table: "realms");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "verification",
|
||||
table: "publishers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "activated_at",
|
||||
table: "badges");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "active_badge",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "verification",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "verified_as",
|
||||
table: "realms",
|
||||
type: "character varying(4096)",
|
||||
maxLength: 4096,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "verified_at",
|
||||
table: "realms",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,144 +0,0 @@
|
||||
using System;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Sphere.Wallet;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class BetterRecyclingFilesAndWalletSubscriptions : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "is_marked_recycle",
|
||||
table: "files",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "location",
|
||||
table: "account_profiles",
|
||||
type: "character varying(1024)",
|
||||
maxLength: 1024,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<SubscriptionReferenceObject>(
|
||||
name: "stellar_membership",
|
||||
table: "account_profiles",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "time_zone",
|
||||
table: "account_profiles",
|
||||
type: "character varying(1024)",
|
||||
maxLength: 1024,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "wallet_coupons",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
identifier = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
||||
code = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
|
||||
affected_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||
discount_amount = table.Column<decimal>(type: "numeric", nullable: true),
|
||||
discount_rate = table.Column<double>(type: "double precision", nullable: true),
|
||||
max_usage = table.Column<int>(type: "integer", 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_wallet_coupons", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "wallet_subscriptions",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
begun_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||
ended_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||
identifier = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
||||
is_active = table.Column<bool>(type: "boolean", nullable: false),
|
||||
is_free_trial = table.Column<bool>(type: "boolean", nullable: false),
|
||||
status = table.Column<int>(type: "integer", nullable: false),
|
||||
payment_method = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
||||
payment_details = table.Column<PaymentDetails>(type: "jsonb", nullable: false),
|
||||
base_price = table.Column<decimal>(type: "numeric", nullable: false),
|
||||
coupon_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
renewal_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||
account_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_wallet_subscriptions", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_wallet_subscriptions_accounts_account_id",
|
||||
column: x => x.account_id,
|
||||
principalTable: "accounts",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "fk_wallet_subscriptions_wallet_coupons_coupon_id",
|
||||
column: x => x.coupon_id,
|
||||
principalTable: "wallet_coupons",
|
||||
principalColumn: "id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_wallet_subscriptions_account_id",
|
||||
table: "wallet_subscriptions",
|
||||
column: "account_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_wallet_subscriptions_coupon_id",
|
||||
table: "wallet_subscriptions",
|
||||
column: "coupon_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_wallet_subscriptions_identifier",
|
||||
table: "wallet_subscriptions",
|
||||
column: "identifier");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "wallet_subscriptions");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "wallet_coupons");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "is_marked_recycle",
|
||||
table: "files");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "location",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "stellar_membership",
|
||||
table: "account_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "time_zone",
|
||||
table: "account_profiles");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,82 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class WalletOrderAppDX : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_payment_orders_wallets_payee_wallet_id",
|
||||
table: "payment_orders");
|
||||
|
||||
migrationBuilder.AlterColumn<Guid>(
|
||||
name: "payee_wallet_id",
|
||||
table: "payment_orders",
|
||||
type: "uuid",
|
||||
nullable: true,
|
||||
oldClrType: typeof(Guid),
|
||||
oldType: "uuid");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "app_identifier",
|
||||
table: "payment_orders",
|
||||
type: "character varying(4096)",
|
||||
maxLength: 4096,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Dictionary<string, object>>(
|
||||
name: "meta",
|
||||
table: "payment_orders",
|
||||
type: "jsonb",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_payment_orders_wallets_payee_wallet_id",
|
||||
table: "payment_orders",
|
||||
column: "payee_wallet_id",
|
||||
principalTable: "wallets",
|
||||
principalColumn: "id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_payment_orders_wallets_payee_wallet_id",
|
||||
table: "payment_orders");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "app_identifier",
|
||||
table: "payment_orders");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "meta",
|
||||
table: "payment_orders");
|
||||
|
||||
migrationBuilder.AlterColumn<Guid>(
|
||||
name: "payee_wallet_id",
|
||||
table: "payment_orders",
|
||||
type: "uuid",
|
||||
nullable: false,
|
||||
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||
oldClrType: typeof(Guid),
|
||||
oldType: "uuid",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_payment_orders_wallets_payee_wallet_id",
|
||||
table: "payment_orders",
|
||||
column: "payee_wallet_id",
|
||||
principalTable: "wallets",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,103 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DysonNetwork.Sphere.Connection.WebReader;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddWebArticles : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "web_feeds",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
url = table.Column<string>(type: "character varying(8192)", maxLength: 8192, nullable: false),
|
||||
title = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
||||
description = table.Column<string>(type: "character varying(8192)", maxLength: 8192, nullable: true),
|
||||
preview = table.Column<LinkEmbed>(type: "jsonb", nullable: true),
|
||||
publisher_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_web_feeds", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_web_feeds_publishers_publisher_id",
|
||||
column: x => x.publisher_id,
|
||||
principalTable: "publishers",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "web_articles",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
title = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
||||
url = table.Column<string>(type: "character varying(8192)", maxLength: 8192, nullable: false),
|
||||
author = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: true),
|
||||
meta = table.Column<Dictionary<string, object>>(type: "jsonb", nullable: true),
|
||||
preview = table.Column<LinkEmbed>(type: "jsonb", nullable: true),
|
||||
content = table.Column<string>(type: "text", nullable: true),
|
||||
published_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
feed_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_web_articles", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_web_articles_web_feeds_feed_id",
|
||||
column: x => x.feed_id,
|
||||
principalTable: "web_feeds",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_web_articles_feed_id",
|
||||
table: "web_articles",
|
||||
column: "feed_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_web_articles_url",
|
||||
table: "web_articles",
|
||||
column: "url",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_web_feeds_publisher_id",
|
||||
table: "web_feeds",
|
||||
column: "publisher_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_web_feeds_url",
|
||||
table: "web_feeds",
|
||||
column: "url",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "web_articles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "web_feeds");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,84 +0,0 @@
|
||||
using System;
|
||||
using DysonNetwork.Sphere.Connection.WebReader;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddRealmTags : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<WebFeedConfig>(
|
||||
name: "config",
|
||||
table: "web_feeds",
|
||||
type: "jsonb",
|
||||
nullable: false);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "tags",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
name = table.Column<string>(type: "character varying(64)", maxLength: 64, 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_tags", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "realm_tags",
|
||||
columns: table => new
|
||||
{
|
||||
realm_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
tag_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_realm_tags", x => new { x.realm_id, x.tag_id });
|
||||
table.ForeignKey(
|
||||
name: "fk_realm_tags_realms_realm_id",
|
||||
column: x => x.realm_id,
|
||||
principalTable: "realms",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "fk_realm_tags_tags_tag_id",
|
||||
column: x => x.tag_id,
|
||||
principalTable: "tags",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_realm_tags_tag_id",
|
||||
table: "realm_tags",
|
||||
column: "tag_id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "realm_tags");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "tags");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "config",
|
||||
table: "web_feeds");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Common.Services.Permission;
|
||||
using DysonNetwork.Sphere.Publisher;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Common.Interfaces;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Common.Services.Permission;
|
||||
using DysonNetwork.Sphere.Realm;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Common.Services.Permission;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Common.Services.Permission;
|
||||
using DysonNetwork.Sphere.Post;
|
||||
using DysonNetwork.Sphere.Publisher;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
|
@ -1,5 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Common.Services.Permission;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
Reference in New Issue
Block a user