:drunk: AI did something
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
using MagicOnion;
|
||||
using MagicOnion.Server;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Shared.Cache;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
|
||||
@@ -9,7 +12,7 @@ namespace DysonNetwork.Pass.Permission;
|
||||
public class PermissionService(
|
||||
AppDatabase db,
|
||||
ICacheService cache
|
||||
)
|
||||
) : ServiceBase<IPermissionService>, IPermissionService
|
||||
{
|
||||
private static readonly TimeSpan CacheExpiration = TimeSpan.FromMinutes(1);
|
||||
|
||||
@@ -195,4 +198,11 @@ public class PermissionService(
|
||||
Value = _SerializePermissionValue(value),
|
||||
};
|
||||
}
|
||||
|
||||
public async UnaryResult<bool> CheckPermission(string scope, string permission)
|
||||
{
|
||||
// Assuming the actor is always "user:current" for client-side checks
|
||||
// You might need to adjust this based on how your client identifies itself
|
||||
return await HasPermissionAsync("user:current", scope, permission);
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,9 @@
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="dotnet-etcd" Version="8.0.1" />
|
||||
<PackageReference Include="MagicOnion.Client" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />
|
||||
<PackageReference Include="MagicOnion.Server" Version="7.0.5" />
|
||||
|
||||
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.6" />
|
||||
|
||||
49
DysonNetwork.Shared/Permission/MagicOnionPermissionFilter.cs
Normal file
49
DysonNetwork.Shared/Permission/MagicOnionPermissionFilter.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using MagicOnion.Server.Filters;
|
||||
using MagicOnion.Server;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace DysonNetwork.Shared.Permission;
|
||||
|
||||
public class MagicOnionPermissionFilter : IMagicOnionFilter<RequiredPermissionAttribute>
|
||||
{
|
||||
private readonly IPermissionService _permissionService;
|
||||
|
||||
public MagicOnionPermissionFilter(IPermissionService permissionService)
|
||||
{
|
||||
_permissionService = permissionService;
|
||||
}
|
||||
|
||||
public async ValueTask Invoke(ServiceContext context, RequiredPermissionAttribute attribute, Func<ServiceContext, ValueTask> next)
|
||||
{
|
||||
var httpContext = context.GetHttpContext();
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new InvalidOperationException("HttpContext is not available in ServiceContext.");
|
||||
}
|
||||
|
||||
if (httpContext.Items["CurrentUser"] is not Account currentUser)
|
||||
{
|
||||
throw new ReturnStatusException(MagicOnion.Grpc.StatusCode.PermissionDenied, "Unauthorized: Current user not found.");
|
||||
}
|
||||
|
||||
if (currentUser.IsSuperuser)
|
||||
{
|
||||
await next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var actor = $"user:{currentUser.Id}";
|
||||
var hasPermission = await _permissionService.CheckPermission(actor, attribute.Scope, attribute.Permission);
|
||||
|
||||
if (!hasPermission)
|
||||
{
|
||||
throw new ReturnStatusException(MagicOnion.Grpc.StatusCode.PermissionDenied, $"Permission {attribute.Scope}/{attribute.Permission} was required.");
|
||||
}
|
||||
|
||||
await next(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using MagicOnion.Server.Filters;
|
||||
|
||||
namespace DysonNetwork.Shared.Permission;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||
public class RequiredPermissionAttribute : MagicOnionFilterAttribute
|
||||
{
|
||||
public string Scope { get; }
|
||||
public string Permission { get; }
|
||||
|
||||
public RequiredPermissionAttribute(string scope, string permission) : base(typeof(MagicOnionPermissionFilter))
|
||||
{
|
||||
Scope = scope;
|
||||
Permission = permission;
|
||||
Order = 999; // Ensure this runs after authentication filters
|
||||
}
|
||||
}
|
||||
8
DysonNetwork.Shared/Services/IPermissionService.cs
Normal file
8
DysonNetwork.Shared/Services/IPermissionService.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using MagicOnion;
|
||||
|
||||
namespace DysonNetwork.Shared.Services;
|
||||
|
||||
public interface IPermissionService : IService<IPermissionService>
|
||||
{
|
||||
UnaryResult<bool> CheckPermission(string scope, string permission);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Connection.WebReader;
|
||||
using DysonNetwork.Sphere.Discovery;
|
||||
using DysonNetwork.Sphere.Post;
|
||||
@@ -11,7 +11,7 @@ namespace DysonNetwork.Sphere.Activity;
|
||||
public class ActivityService(
|
||||
AppDatabase db,
|
||||
PublisherService pub,
|
||||
RelationshipService rels,
|
||||
DysonNetwork.Shared.Services.IRelationshipService rels,
|
||||
PostService ps,
|
||||
DiscoveryService ds
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Connection.WebReader;
|
||||
using DysonNetwork.Sphere.Post;
|
||||
using DysonNetwork.Sphere.Sticker;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -9,15 +10,6 @@ using Microsoft.EntityFrameworkCore.Query;
|
||||
using NodaTime;
|
||||
using Quartz;
|
||||
|
||||
namespace DysonNetwork.Sphere;
|
||||
|
||||
public abstract class ModelBase
|
||||
{
|
||||
public Instant CreatedAt { get; set; }
|
||||
public Instant UpdatedAt { get; set; }
|
||||
public Instant? DeletedAt { get; set; }
|
||||
}
|
||||
|
||||
public class AppDatabase(
|
||||
DbContextOptions<AppDatabase> options,
|
||||
IConfiguration configuration
|
||||
@@ -26,18 +18,18 @@ public class AppDatabase(
|
||||
public DbSet<CloudFile> Files { get; set; }
|
||||
public DbSet<CloudFileReference> FileReferences { get; set; }
|
||||
|
||||
public DbSet<Shared.Models.Publisher> Publishers { get; set; }
|
||||
public DbSet<Publisher> Publishers { get; set; }
|
||||
public DbSet<PublisherMember> PublisherMembers { get; set; }
|
||||
public DbSet<PublisherSubscription> PublisherSubscriptions { get; set; }
|
||||
public DbSet<PublisherFeature> PublisherFeatures { get; set; }
|
||||
|
||||
public DbSet<Post.Post> Posts { get; set; }
|
||||
public DbSet<Post> Posts { get; set; }
|
||||
public DbSet<PostReaction> PostReactions { get; set; }
|
||||
public DbSet<PostTag> PostTags { get; set; }
|
||||
public DbSet<PostCategory> PostCategories { get; set; }
|
||||
public DbSet<PostCollection> PostCollections { get; set; }
|
||||
|
||||
public DbSet<Shared.Models.Realm> Realms { get; set; }
|
||||
public DbSet<Realm> Realms { get; set; }
|
||||
public DbSet<RealmMember> RealmMembers { get; set; }
|
||||
|
||||
public DbSet<ChatRoom> ChatRooms { get; set; }
|
||||
@@ -46,10 +38,10 @@ public class AppDatabase(
|
||||
public DbSet<RealtimeCall> ChatRealtimeCall { get; set; }
|
||||
public DbSet<MessageReaction> ChatReactions { get; set; }
|
||||
|
||||
public DbSet<Sticker.Sticker> Stickers { get; set; }
|
||||
public DbSet<Sticker> Stickers { get; set; }
|
||||
public DbSet<StickerPack> StickerPacks { get; set; }
|
||||
|
||||
public DbSet<Shared.Models.Wallet> Wallets { get; set; }
|
||||
public DbSet<Wallet> Wallets { get; set; }
|
||||
public DbSet<WalletPocket> WalletPockets { get; set; }
|
||||
public DbSet<Order> PaymentOrders { get; set; }
|
||||
public DbSet<Transaction> PaymentTransactions { get; set; }
|
||||
@@ -59,8 +51,8 @@ public class AppDatabase(
|
||||
|
||||
public DbSet<Subscription> WalletSubscriptions { get; set; }
|
||||
public DbSet<Coupon> WalletCoupons { get; set; }
|
||||
public DbSet<Connection.WebReader.WebArticle> WebArticles { get; set; }
|
||||
public DbSet<Connection.WebReader.WebFeed> WebFeeds { get; set; }
|
||||
public DbSet<WebArticle> WebArticles { get; set; }
|
||||
public DbSet<WebFeed> WebFeeds { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
@@ -103,7 +95,7 @@ public class AppDatabase(
|
||||
.HasForeignKey(ps => ps.AccountId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<Post.Post>()
|
||||
modelBuilder.Entity<Post>()
|
||||
.HasGeneratedTsVectorColumn(p => p.SearchVector, "simple", p => new { p.Title, p.Description, p.Content })
|
||||
.HasIndex(p => p.SearchVector)
|
||||
.HasMethod("GIN");
|
||||
@@ -118,25 +110,25 @@ public class AppDatabase(
|
||||
.HasForeignKey(s => s.AppId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<Post.Post>()
|
||||
modelBuilder.Entity<Post>()
|
||||
.HasOne(p => p.RepliedPost)
|
||||
.WithMany()
|
||||
.HasForeignKey(p => p.RepliedPostId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
modelBuilder.Entity<Post.Post>()
|
||||
modelBuilder.Entity<Post>()
|
||||
.HasOne(p => p.ForwardedPost)
|
||||
.WithMany()
|
||||
.HasForeignKey(p => p.ForwardedPostId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
modelBuilder.Entity<Post.Post>()
|
||||
modelBuilder.Entity<Post>()
|
||||
.HasMany(p => p.Tags)
|
||||
.WithMany(t => t.Posts)
|
||||
.UsingEntity(j => j.ToTable("post_tag_links"));
|
||||
modelBuilder.Entity<Post.Post>()
|
||||
modelBuilder.Entity<Post>()
|
||||
.HasMany(p => p.Categories)
|
||||
.WithMany(c => c.Posts)
|
||||
.UsingEntity(j => j.ToTable("post_category_links"));
|
||||
modelBuilder.Entity<Post.Post>()
|
||||
modelBuilder.Entity<Post>()
|
||||
.HasMany(p => p.Collections)
|
||||
.WithMany(c => c.Posts)
|
||||
.UsingEntity(j => j.ToTable("post_collection_links"));
|
||||
@@ -189,11 +181,11 @@ public class AppDatabase(
|
||||
.HasForeignKey(m => m.SenderId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<Connection.WebReader.WebFeed>()
|
||||
modelBuilder.Entity<WebFeed>()
|
||||
.HasIndex(f => f.Url)
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<Connection.WebReader.WebArticle>()
|
||||
modelBuilder.Entity<WebArticle>()
|
||||
.HasIndex(a => a.Url)
|
||||
.IsUnique();
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
|
||||
|
||||
[HttpPost("{roomId:guid}/messages")]
|
||||
[Authorize]
|
||||
[RequiredPermission("global", "chat.messages.create")]
|
||||
[RequiredPermissionAttribute("global", "chat.messages.create")]
|
||||
public async Task<ActionResult> SendMessage([FromBody] SendMessageRequest request, Guid roomId)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
@@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using DysonNetwork.Sphere.Localization;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Sphere.Realm;
|
||||
@@ -20,11 +20,10 @@ public class ChatRoomController(
|
||||
FileReferenceService fileRefService,
|
||||
ChatRoomService crs,
|
||||
RealmService rs,
|
||||
ActionLogService als,
|
||||
NotificationService nty,
|
||||
RelationshipService rels,
|
||||
IStringLocalizer<NotificationResource> localizer,
|
||||
AccountEventService aes
|
||||
DysonNetwork.Shared.Services.IActionLogService als,
|
||||
DysonNetwork.Shared.Services.INotificationService nty,
|
||||
DysonNetwork.Shared.Services.IRelationshipService rels,
|
||||
DysonNetwork.Shared.Services.IAccountEventService aes
|
||||
) : ControllerBase
|
||||
{
|
||||
[HttpGet("{id:guid}")]
|
||||
@@ -162,7 +161,7 @@ public class ChatRoomController(
|
||||
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
[RequiredPermission("global", "chat.create")]
|
||||
[RequiredPermissionAttribute("global", "chat.create")]
|
||||
public async Task<ActionResult<ChatRoom>> CreateChatRoom(ChatRoomRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Sphere.Chat.Realtime;
|
||||
using DysonNetwork.Sphere.Connection;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
|
||||
@@ -59,7 +59,7 @@ public class WebReaderController(WebReaderService reader, ILogger<WebReaderContr
|
||||
/// </summary>
|
||||
[HttpDelete("link/cache")]
|
||||
[Authorize]
|
||||
[RequiredPermission("maintenance", "cache.scrap")]
|
||||
[RequiredPermissionAttribute("maintenance", "cache.scrap")]
|
||||
public async Task<IActionResult> InvalidateCache([FromQuery] string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
@@ -76,7 +76,7 @@ public class WebReaderController(WebReaderService reader, ILogger<WebReaderContr
|
||||
/// </summary>
|
||||
[HttpDelete("cache/all")]
|
||||
[Authorize]
|
||||
[RequiredPermission("maintenance", "cache.scrap")]
|
||||
[RequiredPermissionAttribute("maintenance", "cache.scrap")]
|
||||
public async Task<IActionResult> InvalidateAllCache()
|
||||
{
|
||||
await reader.InvalidateAllCachedPreviewsAsync();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Sphere.Publisher;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Sphere.Publisher;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@@ -14,7 +13,7 @@ namespace DysonNetwork.Sphere.Developer;
|
||||
public class DeveloperController(
|
||||
AppDatabase db,
|
||||
PublisherService ps,
|
||||
ActionLogService als
|
||||
DysonNetwork.Shared.Services.IActionLogService als
|
||||
)
|
||||
: ControllerBase
|
||||
{
|
||||
@@ -91,7 +90,7 @@ public class DeveloperController(
|
||||
|
||||
[HttpPost("{name}/enroll")]
|
||||
[Authorize]
|
||||
[RequiredPermission("global", "developers.create")]
|
||||
[RequiredPermissionAttribute("global", "developers.create")]
|
||||
public async Task<ActionResult<Shared.Models.Publisher>> EnrollDeveloperProgram(string name)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
@@ -172,6 +172,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DysonNetwork.Shared\DysonNetwork.Shared.csproj" />
|
||||
<ProjectReference Include="..\DysonNetwork.Pass\DysonNetwork.Pass.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using DysonNetwork.Sphere.Auth;
|
||||
using DysonNetwork.Pass.Auth;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using DysonNetwork.Sphere.Auth.OidcProvider.Services;
|
||||
using DysonNetwork.Pass.Auth;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Auth.OidcProvider.Responses;
|
||||
using DysonNetwork.Pass.Auth;
|
||||
using DysonNetwork.Sphere.Developer;
|
||||
|
||||
namespace DysonNetwork.Sphere.Pages.Auth;
|
||||
|
||||
public class AuthorizeModel(OidcProviderService oidcService, IConfiguration configuration) : PageModel
|
||||
public class AuthorizeModel( DysonNetwork.Pass.Auth.OidcProvider.Services.OidcProviderService oidcService, IConfiguration configuration) : PageModel
|
||||
{
|
||||
[BindProperty(SupportsGet = true)] public string? ReturnUrl { get; set; }
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Auth;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Pass.Auth;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using DysonNetwork.Sphere.Connection;
|
||||
using NodaTime;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -12,10 +12,10 @@ namespace DysonNetwork.Sphere.Pages.Auth
|
||||
{
|
||||
public class LoginModel(
|
||||
AppDatabase db,
|
||||
AccountService accounts,
|
||||
AuthService auth,
|
||||
DysonNetwork.Shared.Services.IAccountService accounts,
|
||||
DysonNetwork.Pass.Auth.AuthService auth,
|
||||
GeoIpService geo,
|
||||
ActionLogService als
|
||||
DysonNetwork.Shared.Services.IActionLogService als
|
||||
) : PageModel
|
||||
{
|
||||
[BindProperty] [Required] public string Username { get; set; } = string.Empty;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
@page "/web/auth/challenge/{id:guid}/select-factor"
|
||||
@using DysonNetwork.Shared.Models
|
||||
@using DysonNetwork.Sphere.Account
|
||||
@model DysonNetwork.Sphere.Pages.Auth.SelectFactorModel
|
||||
@{
|
||||
ViewData["Title"] = "Select Authentication Method";
|
||||
|
||||
@@ -2,8 +2,8 @@ using DysonNetwork.Shared.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DysonNetwork.Sphere.Auth;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Pass.Auth;
|
||||
using DysonNetwork.Pass.Account;
|
||||
|
||||
namespace DysonNetwork.Sphere.Pages.Auth;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@page "/web/auth/challenge/{id:guid}/verify/{factorId:guid}"
|
||||
@using DysonNetwork.Shared.Models
|
||||
@using DysonNetwork.Sphere.Account
|
||||
@using DysonNetwork.Shared.Models
|
||||
@model DysonNetwork.Sphere.Pages.Auth.VerifyFactorModel
|
||||
@{
|
||||
ViewData["Title"] = "Verify Your Identity";
|
||||
|
||||
@@ -3,17 +3,17 @@ using DysonNetwork.Shared.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DysonNetwork.Sphere.Auth;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Sphere.Pages.Auth
|
||||
{
|
||||
public class VerifyFactorModel(
|
||||
AppDatabase db,
|
||||
AccountService accounts,
|
||||
AuthService auth,
|
||||
ActionLogService als,
|
||||
DysonNetwork.Shared.Services.IAccountService accountService,
|
||||
DysonNetwork.Pass.Auth.AuthService authService,
|
||||
DysonNetwork.Shared.Services.IActionLogService actionLogService,
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@using DysonNetwork.Sphere.Auth
|
||||
using DysonNetwork.Pass.Auth;
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-full">
|
||||
<head>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@page "/spells/{spellWord}"
|
||||
@using DysonNetwork.Sphere.Account
|
||||
@using DysonNetwork.Shared.Models
|
||||
@model DysonNetwork.Sphere.Pages.Spell.MagicSpellPage
|
||||
|
||||
@{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -6,7 +6,7 @@ using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Sphere.Pages.Spell;
|
||||
|
||||
public class MagicSpellPage(AppDatabase db, MagicSpellService spells) : PageModel
|
||||
public class MagicSpellPage(AppDatabase db, DysonNetwork.Shared.Services.IMagicSpellService magicSpellService) : PageModel
|
||||
{
|
||||
[BindProperty] public MagicSpell? CurrentSpell { get; set; }
|
||||
[BindProperty] public string? NewPassword { get; set; }
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using MagicOnion;
|
||||
|
||||
namespace DysonNetwork.Sphere.Permission;
|
||||
|
||||
public class RequiredPermissionAttribute : TypeFilterAttribute
|
||||
{
|
||||
public RequiredPermissionAttribute(string scope, string permission) : base(typeof(RequiredPermissionFilter))
|
||||
{
|
||||
Arguments = new object[] { scope, permission };
|
||||
}
|
||||
|
||||
private class RequiredPermissionFilter : IAsyncActionFilter
|
||||
{
|
||||
private readonly IPermissionService _permissionService;
|
||||
private readonly string _scope;
|
||||
private readonly string _permission;
|
||||
|
||||
public RequiredPermissionFilter(IPermissionService permissionService, string scope, string permission)
|
||||
{
|
||||
_permissionService = permissionService;
|
||||
_scope = scope;
|
||||
_permission = permission;
|
||||
}
|
||||
|
||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
// Assuming the actor is always "user:current" for client-side checks
|
||||
// You might need to adjust this based on how your client identifies itself
|
||||
var hasPermission = await _permissionService.CheckPermission(_scope, _permission);
|
||||
|
||||
if (!hasPermission)
|
||||
{
|
||||
context.Result = new ForbidResult();
|
||||
return;
|
||||
}
|
||||
|
||||
await next();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Sphere.Publisher;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
@@ -19,8 +19,8 @@ public class PostController(
|
||||
AppDatabase db,
|
||||
PostService ps,
|
||||
PublisherService pub,
|
||||
RelationshipService rels,
|
||||
ActionLogService als
|
||||
DysonNetwork.Shared.Services.IRelationshipService rels,
|
||||
DysonNetwork.Shared.Services.IActionLogService als
|
||||
)
|
||||
: ControllerBase
|
||||
{
|
||||
@@ -280,7 +280,7 @@ public class PostController(
|
||||
|
||||
[HttpPost("{id:guid}/reactions")]
|
||||
[Authorize]
|
||||
[RequiredPermission("global", "posts.react")]
|
||||
[RequiredPermissionAttribute("global", "posts.react")]
|
||||
public async Task<ActionResult<PostReaction>> ReactPost(Guid id, [FromBody] PostReactionRequest request)
|
||||
{
|
||||
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using DysonNetwork.Shared.Cache;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Connection.WebReader;
|
||||
using DysonNetwork.Sphere.Localization;
|
||||
using DysonNetwork.Sphere.Publisher;
|
||||
|
||||
@@ -48,7 +48,7 @@ var tusDiskStore = app.Services.GetRequiredService<TusDiskStore>();
|
||||
app.ConfigureAppMiddleware(builder.Configuration, tusDiskStore);
|
||||
|
||||
// Map gRPC services
|
||||
app.MapGrpcService<DysonNetwork.Sphere.Auth.AuthGrpcService>();
|
||||
app.MapGrpcService<DysonNetwork.Sphere.Account.AccountGrpcService>();
|
||||
app.MapGrpcService<DysonNetwork.Pass.Auth.AuthGrpcService>();
|
||||
app.MapGrpcService<DysonNetwork.Pass.Account.AccountGrpcService>();
|
||||
|
||||
app.Run();
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Sphere.Realm;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
@@ -17,7 +16,7 @@ public class PublisherController(
|
||||
AppDatabase db,
|
||||
PublisherService ps,
|
||||
FileReferenceService fileRefService,
|
||||
ActionLogService als)
|
||||
DysonNetwork.Shared.Services.IActionLogService als)
|
||||
: ControllerBase
|
||||
{
|
||||
[HttpGet("{name}")]
|
||||
@@ -531,7 +530,7 @@ public class PublisherController(
|
||||
|
||||
[HttpPost("{name}/features")]
|
||||
[Authorize]
|
||||
[RequiredPermission("maintenance", "publishers.features")]
|
||||
[RequiredPermissionAttribute("maintenance", "publishers.features")]
|
||||
public async Task<ActionResult<PublisherFeature>> AddPublisherFeature(string name,
|
||||
[FromBody] PublisherFeatureRequest request)
|
||||
{
|
||||
@@ -555,7 +554,7 @@ public class PublisherController(
|
||||
|
||||
[HttpDelete("{name}/features/{flag}")]
|
||||
[Authorize]
|
||||
[RequiredPermission("maintenance", "publishers.features")]
|
||||
[RequiredPermissionAttribute("maintenance", "publishers.features")]
|
||||
public async Task<ActionResult> RemovePublisherFeature(string name, string flag)
|
||||
{
|
||||
var publisher = await db.Publishers
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using DysonNetwork.Shared.Cache;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Pass.Account;
|
||||
using DysonNetwork.Sphere.Localization;
|
||||
using DysonNetwork.Sphere.Post;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Pass.Account;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Sphere.Localization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace DysonNetwork.Sphere.Realm;
|
||||
|
||||
public class RealmService(AppDatabase db, NotificationService nty, IStringLocalizer<NotificationResource> localizer)
|
||||
public class RealmService(AppDatabase db, DysonNetwork.Shared.Services.INotificationService nty, IStringLocalizer<NotificationResource> localizer)
|
||||
{
|
||||
public async Task SendInviteNotify(RealmMember member)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Pass.Account;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -122,7 +122,7 @@ public class AbuseReportController(
|
||||
|
||||
[HttpPost("{id}/resolve")]
|
||||
[Authorize]
|
||||
[RequiredPermission("safety", "reports.resolve")]
|
||||
[RequiredPermissionAttribute("safety", "reports.resolve")]
|
||||
[ProducesResponseType<AbuseReport>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<AbuseReport>> ResolveReport(Guid id, [FromBody] ResolveReportRequest request)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Pass.Account;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ using DysonNetwork.Sphere.Discovery;
|
||||
using DysonNetwork.Sphere.Safety;
|
||||
using DysonNetwork.Sphere.Wallet.PaymentHandlers;
|
||||
using tusdotnet.Stores;
|
||||
using DysonNetwork.Shared.Etcd;
|
||||
using DysonNetwork.Shared.Services;
|
||||
|
||||
namespace DysonNetwork.Sphere.Startup;
|
||||
|
||||
@@ -207,6 +209,15 @@ public static class ServiceCollectionExtensions
|
||||
services.AddScoped<DiscoveryService>();
|
||||
services.AddScoped<CustomAppService>();
|
||||
|
||||
// Add MagicOnion services
|
||||
services.AddMagicOnionService<IAccountService>();
|
||||
services.AddMagicOnionService<IAccountEventService>();
|
||||
services.AddMagicOnionService<IAccountUsernameService>();
|
||||
services.AddMagicOnionService<IActionLogService>();
|
||||
services.AddMagicOnionService<IMagicSpellService>();
|
||||
services.AddMagicOnionService<INotificationService>();
|
||||
services.AddMagicOnionService<IRelationshipService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -271,7 +271,7 @@ public class StickerController(AppDatabase db, StickerService st) : ControllerBa
|
||||
public const int MaxStickersPerPack = 24;
|
||||
|
||||
[HttpPost("{packId:guid}/content")]
|
||||
[RequiredPermission("global", "stickers.create")]
|
||||
[RequiredPermissionAttribute("global", "stickers.create")]
|
||||
public async Task<IActionResult> CreateSticker(Guid packId, [FromBody] StickerRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser)
|
||||
|
||||
@@ -111,7 +111,7 @@ public class FileController(
|
||||
|
||||
[HttpPost("/maintenance/migrateReferences")]
|
||||
[Authorize]
|
||||
[RequiredPermission("maintenance", "files.references")]
|
||||
[RequiredPermissionAttribute("maintenance", "files.references")]
|
||||
public async Task<ActionResult> MigrateFileReferences()
|
||||
{
|
||||
await rms.ScanAndMigrateReferences();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using EFCore.BulkExtensions;
|
||||
using Quartz;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Pass.Permission;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using tusdotnet.Interfaces;
|
||||
@@ -10,7 +10,7 @@ using tusdotnet.Models.Configuration;
|
||||
|
||||
namespace DysonNetwork.Sphere.Storage;
|
||||
|
||||
public abstract class TusService
|
||||
public class TusService(DefaultTusConfiguration config, ITusStore store)
|
||||
{
|
||||
public static DefaultTusConfiguration BuildConfiguration(ITusStore store) => new()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Auth;
|
||||
using DysonNetwork.Pass.Auth;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Globalization;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Sphere.Localization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
@@ -12,7 +11,7 @@ namespace DysonNetwork.Sphere.Wallet;
|
||||
public class PaymentService(
|
||||
AppDatabase db,
|
||||
WalletService wat,
|
||||
NotificationService nty,
|
||||
DysonNetwork.Shared.Services.INotificationService nty,
|
||||
IStringLocalizer<NotificationResource> localizer
|
||||
)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Shared.Cache;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using DysonNetwork.Sphere.Localization;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using DysonNetwork.Sphere.Wallet.PaymentHandlers;
|
||||
@@ -14,8 +14,8 @@ namespace DysonNetwork.Sphere.Wallet;
|
||||
public class SubscriptionService(
|
||||
AppDatabase db,
|
||||
PaymentService payment,
|
||||
AccountService accounts,
|
||||
NotificationService nty,
|
||||
DysonNetwork.Shared.Services.IAccountService account,
|
||||
DysonNetwork.Shared.Services.INotificationService nty,
|
||||
IStringLocalizer<NotificationResource> localizer,
|
||||
IConfiguration configuration,
|
||||
ICacheService cache,
|
||||
|
||||
@@ -75,7 +75,7 @@ public class WalletController(AppDatabase db, WalletService ws, PaymentService p
|
||||
|
||||
[HttpPost("balance")]
|
||||
[Authorize]
|
||||
[RequiredPermission("maintenance", "wallets.balance.modify")]
|
||||
[RequiredPermissionAttribute("maintenance", "wallets.balance.modify")]
|
||||
public async Task<ActionResult<Transaction>> ModifyWalletBalance([FromBody] WalletBalanceRequest request)
|
||||
{
|
||||
var wallet = await ws.GetWalletAsync(request.AccountId);
|
||||
|
||||
Reference in New Issue
Block a user