♻️ Move most of models to the Shared package

This commit is contained in:
2025-07-06 22:34:52 +08:00
parent cb4acbb3fc
commit 65450e8511
170 changed files with 679 additions and 101121 deletions

View File

@ -1,104 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using DysonNetwork.Sphere.Post;
using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore;
using NodaTime;
namespace DysonNetwork.Sphere.Publisher;
public enum PublisherType
{
Individual,
Organizational
}
[Index(nameof(Name), IsUnique = true)]
public class Publisher : ModelBase, IIdentifiedResource
{
public Guid Id { get; set; }
public PublisherType Type { get; set; }
[MaxLength(256)] public string Name { get; set; } = string.Empty;
[MaxLength(256)] public string Nick { get; set; } = string.Empty;
[MaxLength(4096)] public string? Bio { get; set; }
// Outdated fields, for backward compability
[MaxLength(32)] public string? PictureId { get; set; }
[MaxLength(32)] public string? BackgroundId { get; set; }
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Picture { get; set; }
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Background { get; set; }
[Column(TypeName = "jsonb")] public Account.VerificationMark? Verification { get; set; }
[JsonIgnore] public ICollection<Post.Post> Posts { get; set; } = new List<Post.Post>();
[JsonIgnore] public ICollection<PostCollection> Collections { get; set; } = new List<PostCollection>();
[JsonIgnore] public ICollection<PublisherMember> Members { get; set; } = new List<PublisherMember>();
[JsonIgnore] public ICollection<PublisherFeature> Features { get; set; } = new List<PublisherFeature>();
[JsonIgnore]
public ICollection<PublisherSubscription> Subscriptions { get; set; } = new List<PublisherSubscription>();
public Guid? AccountId { get; set; }
public Account.Account? Account { get; set; }
public Guid? RealmId { get; set; }
[JsonIgnore] public Realm.Realm? Realm { get; set; }
public string ResourceIdentifier => $"publisher/{Id}";
}
public enum PublisherMemberRole
{
Owner = 100,
Manager = 75,
Editor = 50,
Viewer = 25
}
public class PublisherMember : ModelBase
{
public Guid PublisherId { get; set; }
[JsonIgnore] public Publisher Publisher { get; set; } = null!;
public Guid AccountId { get; set; }
public Account.Account Account { get; set; } = null!;
public PublisherMemberRole Role { get; set; } = PublisherMemberRole.Viewer;
public Instant? JoinedAt { get; set; }
}
public enum PublisherSubscriptionStatus
{
Active,
Expired,
Cancelled
}
public class PublisherSubscription : ModelBase
{
public Guid Id { get; set; }
public Guid PublisherId { get; set; }
[JsonIgnore] public Publisher Publisher { get; set; } = null!;
public Guid AccountId { get; set; }
[JsonIgnore] public Account.Account Account { get; set; } = null!;
public PublisherSubscriptionStatus Status { get; set; } = PublisherSubscriptionStatus.Active;
public int Tier { get; set; } = 0;
}
public class PublisherFeature : ModelBase
{
public Guid Id { get; set; }
[MaxLength(1024)] public string Flag { get; set; } = null!;
public Instant? ExpiredAt { get; set; }
public Guid PublisherId { get; set; }
public Publisher Publisher { get; set; } = null!;
}
public abstract class PublisherFeatureFlag
{
public static List<string> AllFlags => [Develop];
public static string Develop = "develop";
}

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Permission;
using DysonNetwork.Sphere.Realm;
@ -20,7 +21,7 @@ public class PublisherController(
: ControllerBase
{
[HttpGet("{name}")]
public async Task<ActionResult<Publisher>> GetPublisher(string name)
public async Task<ActionResult<Shared.Models.Publisher>> GetPublisher(string name)
{
var publisher = await db.Publishers
.Where(e => e.Name == name)
@ -47,9 +48,9 @@ public class PublisherController(
[HttpGet]
[Authorize]
public async Task<ActionResult<List<Publisher>>> ListManagedPublishers()
public async Task<ActionResult<List<Shared.Models.Publisher>>> ListManagedPublishers()
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id;
var members = await db.PublisherMembers
@ -65,7 +66,7 @@ public class PublisherController(
[Authorize]
public async Task<ActionResult<List<PublisherMember>>> ListInvites()
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id;
var members = await db.PublisherMembers
@ -88,7 +89,7 @@ public class PublisherController(
public async Task<ActionResult<PublisherMember>> InviteMember(string name,
[FromBody] PublisherMemberRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id;
var relatedUser = await db.Accounts.FindAsync(request.RelatedUserId);
@ -126,9 +127,9 @@ public class PublisherController(
[HttpPost("invites/{name}/accept")]
[Authorize]
public async Task<ActionResult<Publisher>> AcceptMemberInvite(string name)
public async Task<ActionResult<Shared.Models.Publisher>> AcceptMemberInvite(string name)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id;
var member = await db.PublisherMembers
@ -154,7 +155,7 @@ public class PublisherController(
[Authorize]
public async Task<ActionResult> DeclineMemberInvite(string name)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id;
var member = await db.PublisherMembers
@ -179,7 +180,7 @@ public class PublisherController(
[Authorize]
public async Task<ActionResult> RemoveMember(string name, Guid memberId)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var publisher = await db.Publishers
.Where(p => p.Name == name)
@ -222,9 +223,9 @@ public class PublisherController(
[HttpPost("individual")]
[Authorize]
[RequiredPermission("global", "publishers.create")]
public async Task<ActionResult<Publisher>> CreatePublisherIndividual([FromBody] PublisherRequest request)
public async Task<ActionResult<Shared.Models.Publisher>> CreatePublisherIndividual([FromBody] PublisherRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var takenName = request.Name ?? currentUser.Name;
var duplicateNameCount = await db.Publishers
@ -271,10 +272,10 @@ public class PublisherController(
[HttpPost("organization/{realmSlug}")]
[Authorize]
[RequiredPermission("global", "publishers.create")]
public async Task<ActionResult<Publisher>> CreatePublisherOrganization(string realmSlug,
public async Task<ActionResult<Shared.Models.Publisher>> CreatePublisherOrganization(string realmSlug,
[FromBody] PublisherRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var realm = await db.Realms.FirstOrDefaultAsync(r => r.Slug == realmSlug);
if (realm == null) return NotFound("Realm not found");
@ -326,9 +327,9 @@ public class PublisherController(
[HttpPatch("{name}")]
[Authorize]
public async Task<ActionResult<Publisher>> UpdatePublisher(string name, PublisherRequest request)
public async Task<ActionResult<Shared.Models.Publisher>> UpdatePublisher(string name, PublisherRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id;
var publisher = await db.Publishers
@ -403,9 +404,9 @@ public class PublisherController(
[HttpDelete("{name}")]
[Authorize]
public async Task<ActionResult<Publisher>> DeletePublisher(string name)
public async Task<ActionResult<Shared.Models.Publisher>> DeletePublisher(string name)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id;
var publisher = await db.Publishers
@ -473,7 +474,7 @@ public class PublisherController(
[Authorize]
public async Task<ActionResult<PublisherMember>> GetCurrentIdentity(string name)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var userId = currentUser.Id;
var publisher = await db.Publishers

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Post;
using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore;
@ -8,7 +9,7 @@ namespace DysonNetwork.Sphere.Publisher;
public class PublisherService(AppDatabase db, FileReferenceService fileRefService, ICacheService cache)
{
public async Task<Publisher?> GetPublisherByName(string name)
public async Task<Shared.Models.Publisher?> GetPublisherByName(string name)
{
return await db.Publishers
.Where(e => e.Name == name)
@ -17,12 +18,12 @@ public class PublisherService(AppDatabase db, FileReferenceService fileRefServic
private const string UserPublishersCacheKey = "accounts:{0}:publishers";
public async Task<List<Publisher>> GetUserPublishers(Guid userId)
public async Task<List<Shared.Models.Publisher>> GetUserPublishers(Guid userId)
{
var cacheKey = string.Format(UserPublishersCacheKey, userId);
// Try to get publishers from the cache first
var publishers = await cache.GetAsync<List<Publisher>>(cacheKey);
var publishers = await cache.GetAsync<List<Shared.Models.Publisher>>(cacheKey);
if (publishers is not null)
return publishers;
@ -41,16 +42,16 @@ public class PublisherService(AppDatabase db, FileReferenceService fileRefServic
return publishers;
}
public async Task<Dictionary<Guid, List<Publisher>>> GetUserPublishersBatch(List<Guid> userIds)
public async Task<Dictionary<Guid, List<Shared.Models.Publisher>>> GetUserPublishersBatch(List<Guid> userIds)
{
var result = new Dictionary<Guid, List<Publisher>>();
var result = new Dictionary<Guid, List<Shared.Models.Publisher>>();
var missingIds = new List<Guid>();
// Try to get publishers from cache for each user
foreach (var userId in userIds)
{
var cacheKey = string.Format(UserPublishersCacheKey, userId);
var publishers = await cache.GetAsync<List<Publisher>>(cacheKey);
var publishers = await cache.GetAsync<List<Shared.Models.Publisher>>(cacheKey);
if (publishers != null)
result[userId] = publishers;
else
@ -97,12 +98,12 @@ public class PublisherService(AppDatabase db, FileReferenceService fileRefServic
public const string SubscribedPublishersCacheKey = "accounts:{0}:subscribed-publishers";
public async Task<List<Publisher>> GetSubscribedPublishers(Guid userId)
public async Task<List<Shared.Models.Publisher>> GetSubscribedPublishers(Guid userId)
{
var cacheKey = string.Format(SubscribedPublishersCacheKey, userId);
// Try to get publishers from the cache first
var publishers = await cache.GetAsync<List<Publisher>>(cacheKey);
var publishers = await cache.GetAsync<List<Shared.Models.Publisher>>(cacheKey);
if (publishers is not null)
return publishers;
@ -146,8 +147,8 @@ public class PublisherService(AppDatabase db, FileReferenceService fileRefServic
return members;
}
public async Task<Publisher> CreateIndividualPublisher(
Account.Account account,
public async Task<Shared.Models.Publisher> CreateIndividualPublisher(
Shared.Models.Account account,
string? name,
string? nick,
string? bio,
@ -155,7 +156,7 @@ public class PublisherService(AppDatabase db, FileReferenceService fileRefServic
CloudFile? background
)
{
var publisher = new Publisher
var publisher = new Shared.Models.Publisher
{
Type = PublisherType.Individual,
Name = name ?? account.Name,
@ -199,9 +200,9 @@ public class PublisherService(AppDatabase db, FileReferenceService fileRefServic
return publisher;
}
public async Task<Publisher> CreateOrganizationPublisher(
Realm.Realm realm,
Account.Account account,
public async Task<Shared.Models.Publisher> CreateOrganizationPublisher(
Shared.Models.Realm realm,
Shared.Models.Account account,
string? name,
string? nick,
string? bio,
@ -209,7 +210,7 @@ public class PublisherService(AppDatabase db, FileReferenceService fileRefServic
CloudFile? background
)
{
var publisher = new Publisher
var publisher = new Shared.Models.Publisher
{
Type = PublisherType.Organizational,
Name = name ?? realm.Slug,

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Post;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@ -30,7 +31,7 @@ public class PublisherSubscriptionController(
[Authorize]
public async Task<ActionResult<SubscriptionStatusResponse>> CheckSubscriptionStatus(string name)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
// Check if the publisher exists
var publisher = await db.Publishers.FirstOrDefaultAsync(p => p.Name == name);
@ -53,7 +54,7 @@ public class PublisherSubscriptionController(
string name,
[FromBody] SubscribeRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
// Check if the publisher exists
var publisher = await db.Publishers.FirstOrDefaultAsync(p => p.Name == name);
@ -81,7 +82,7 @@ public class PublisherSubscriptionController(
[Authorize]
public async Task<ActionResult> Unsubscribe(string name)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
// Check if the publisher exists
var publisher = await db.Publishers.FirstOrDefaultAsync(e => e.Name == name);
@ -104,7 +105,7 @@ public class PublisherSubscriptionController(
[Authorize]
public async Task<ActionResult<List<PublisherSubscription>>> GetCurrentSubscriptions()
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not Shared.Models.Account currentUser) return Unauthorized();
var subscriptions = await subs.GetAccountSubscriptionsAsync(currentUser.Id);
return subscriptions;

View File

@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Sphere.Account;
using DysonNetwork.Sphere.Localization;
using DysonNetwork.Sphere.Post;