✨ Realm tags and discovery
This commit is contained in:
parent
f170793928
commit
d492c9ce1f
@ -75,6 +75,8 @@ public class AppDatabase(
|
|||||||
|
|
||||||
public DbSet<Realm.Realm> Realms { get; set; }
|
public DbSet<Realm.Realm> Realms { get; set; }
|
||||||
public DbSet<RealmMember> RealmMembers { get; set; }
|
public DbSet<RealmMember> RealmMembers { get; set; }
|
||||||
|
public DbSet<Tag> Tags { get; set; }
|
||||||
|
public DbSet<RealmTag> RealmTags { get; set; }
|
||||||
|
|
||||||
public DbSet<ChatRoom> ChatRooms { get; set; }
|
public DbSet<ChatRoom> ChatRooms { get; set; }
|
||||||
public DbSet<ChatMember> ChatMembers { get; set; }
|
public DbSet<ChatMember> ChatMembers { get; set; }
|
||||||
@ -230,6 +232,19 @@ public class AppDatabase(
|
|||||||
.HasForeignKey(pm => pm.AccountId)
|
.HasForeignKey(pm => pm.AccountId)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
modelBuilder.Entity<RealmTag>()
|
||||||
|
.HasKey(rt => new { rt.RealmId, rt.TagId });
|
||||||
|
modelBuilder.Entity<RealmTag>()
|
||||||
|
.HasOne(rt => rt.Realm)
|
||||||
|
.WithMany(r => r.RealmTags)
|
||||||
|
.HasForeignKey(rt => rt.RealmId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
modelBuilder.Entity<RealmTag>()
|
||||||
|
.HasOne(rt => rt.Tag)
|
||||||
|
.WithMany(t => t.RealmTags)
|
||||||
|
.HasForeignKey(rt => rt.TagId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
modelBuilder.Entity<ChatMember>()
|
modelBuilder.Entity<ChatMember>()
|
||||||
.HasKey(pm => new { pm.Id });
|
.HasKey(pm => new { pm.Id });
|
||||||
modelBuilder.Entity<ChatMember>()
|
modelBuilder.Entity<ChatMember>()
|
||||||
|
@ -15,7 +15,8 @@ public class WebFeedService(
|
|||||||
WebReaderService webReaderService
|
WebReaderService webReaderService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
public async Task<WebFeed> CreateWebFeedAsync(WebFeedController.CreateWebFeedRequest request, ClaimsPrincipal claims)
|
public async Task<WebFeed> CreateWebFeedAsync(WebFeedController.CreateWebFeedRequest request,
|
||||||
|
ClaimsPrincipal claims)
|
||||||
{
|
{
|
||||||
if (claims.Identity?.Name == null)
|
if (claims.Identity?.Name == null)
|
||||||
{
|
{
|
||||||
|
17
DysonNetwork.Sphere/Discovery/DiscoveryController.cs
Normal file
17
DysonNetwork.Sphere/Discovery/DiscoveryController.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using DysonNetwork.Sphere.Realm;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Sphere.Discovery;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("discovery")]
|
||||||
|
public class DiscoveryController(DiscoveryService discoveryService) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet("realms")]
|
||||||
|
public Task<List<Realm.Realm>> GetPublicRealms([FromQuery] string? query, [FromQuery] List<string>? tags)
|
||||||
|
{
|
||||||
|
return discoveryService.GetPublicRealmsAsync(query, tags);
|
||||||
|
}
|
||||||
|
}
|
29
DysonNetwork.Sphere/Discovery/DiscoveryService.cs
Normal file
29
DysonNetwork.Sphere/Discovery/DiscoveryService.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using DysonNetwork.Sphere;
|
||||||
|
using DysonNetwork.Sphere.Realm;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Sphere.Discovery;
|
||||||
|
|
||||||
|
public class DiscoveryService(AppDatabase appDatabase)
|
||||||
|
{
|
||||||
|
public Task<List<Realm.Realm>> GetPublicRealmsAsync(string? query, List<string>? tags)
|
||||||
|
{
|
||||||
|
var realmsQuery = appDatabase.Realms
|
||||||
|
.Where(r => r.IsPublic);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(query))
|
||||||
|
{
|
||||||
|
realmsQuery = realmsQuery.Where(r => r.Name.Contains(query) || r.Description.Contains(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags != null && tags.Count > 0)
|
||||||
|
{
|
||||||
|
realmsQuery = realmsQuery.Where(r => r.RealmTags.Any(rt => tags.Contains(rt.Tag.Name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return realmsQuery.ToListAsync();
|
||||||
|
}
|
||||||
|
}
|
@ -84,6 +84,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Migrations\" />
|
<Folder Include="Migrations\" />
|
||||||
|
<Folder Include="Discovery\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
3947
DysonNetwork.Sphere/Migrations/20250626105203_AddRealmTags.Designer.cs
generated
Normal file
3947
DysonNetwork.Sphere/Migrations/20250626105203_AddRealmTags.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,84 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1438,6 +1438,11 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("uuid")
|
.HasColumnType("uuid")
|
||||||
.HasColumnName("id");
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<WebFeedConfig>("Config")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("config");
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
b.Property<Instant>("CreatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("created_at");
|
.HasColumnName("created_at");
|
||||||
@ -2359,6 +2364,68 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
b.ToTable("realm_members", (string)null);
|
b.ToTable("realm_members", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmTag", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("RealmId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("realm_id");
|
||||||
|
|
||||||
|
b.Property<Guid>("TagId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("tag_id");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<Instant>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
|
b.HasKey("RealmId", "TagId")
|
||||||
|
.HasName("pk_realm_tags");
|
||||||
|
|
||||||
|
b.HasIndex("TagId")
|
||||||
|
.HasDatabaseName("ix_realm_tags_tag_id");
|
||||||
|
|
||||||
|
b.ToTable("realm_tags", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Sphere.Realm.Tag", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<Instant>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_tags");
|
||||||
|
|
||||||
|
b.ToTable("tags", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@ -3573,6 +3640,27 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
b.Navigation("Realm");
|
b.Navigation("Realm");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmTag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm")
|
||||||
|
.WithMany("RealmTags")
|
||||||
|
.HasForeignKey("RealmId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_realm_tags_realms_realm_id");
|
||||||
|
|
||||||
|
b.HasOne("DysonNetwork.Sphere.Realm.Tag", "Tag")
|
||||||
|
.WithMany("RealmTags")
|
||||||
|
.HasForeignKey("TagId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_realm_tags_tags_tag_id");
|
||||||
|
|
||||||
|
b.Navigation("Realm");
|
||||||
|
|
||||||
|
b.Navigation("Tag");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("DysonNetwork.Sphere.Sticker.StickerPack", "Pack")
|
b.HasOne("DysonNetwork.Sphere.Sticker.StickerPack", "Pack")
|
||||||
@ -3837,6 +3925,13 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
b.Navigation("ChatRooms");
|
b.Navigation("ChatRooms");
|
||||||
|
|
||||||
b.Navigation("Members");
|
b.Navigation("Members");
|
||||||
|
|
||||||
|
b.Navigation("RealmTags");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Sphere.Realm.Tag", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("RealmTags");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", b =>
|
||||||
|
@ -29,6 +29,7 @@ public class Realm : ModelBase, IIdentifiedResource
|
|||||||
|
|
||||||
[JsonIgnore] public ICollection<RealmMember> Members { get; set; } = new List<RealmMember>();
|
[JsonIgnore] public ICollection<RealmMember> Members { get; set; } = new List<RealmMember>();
|
||||||
[JsonIgnore] public ICollection<ChatRoom> ChatRooms { get; set; } = new List<ChatRoom>();
|
[JsonIgnore] public ICollection<ChatRoom> ChatRooms { get; set; } = new List<ChatRoom>();
|
||||||
|
[JsonIgnore] public ICollection<RealmTag> RealmTags { get; set; } = new List<RealmTag>();
|
||||||
|
|
||||||
public Guid AccountId { get; set; }
|
public Guid AccountId { get; set; }
|
||||||
[JsonIgnore] public Account.Account Account { get; set; } = null!;
|
[JsonIgnore] public Account.Account Account { get; set; } = null!;
|
||||||
|
12
DysonNetwork.Sphere/Realm/RealmTag.cs
Normal file
12
DysonNetwork.Sphere/Realm/RealmTag.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Sphere.Realm;
|
||||||
|
|
||||||
|
public class RealmTag : ModelBase
|
||||||
|
{
|
||||||
|
public Guid RealmId { get; set; }
|
||||||
|
public Realm Realm { get; set; } = null!;
|
||||||
|
|
||||||
|
public Guid TagId { get; set; }
|
||||||
|
public Tag Tag { get; set; } = null!;
|
||||||
|
}
|
14
DysonNetwork.Sphere/Realm/Tag.cs
Normal file
14
DysonNetwork.Sphere/Realm/Tag.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Sphere.Realm;
|
||||||
|
|
||||||
|
public class Tag : ModelBase
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
[MaxLength(64)]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public ICollection<RealmTag> RealmTags { get; set; } = new List<RealmTag>();
|
||||||
|
}
|
@ -25,6 +25,7 @@ using StackExchange.Redis;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.RateLimiting;
|
using System.Threading.RateLimiting;
|
||||||
using DysonNetwork.Sphere.Connection.WebReader;
|
using DysonNetwork.Sphere.Connection.WebReader;
|
||||||
|
using DysonNetwork.Sphere.Discovery;
|
||||||
using DysonNetwork.Sphere.Safety;
|
using DysonNetwork.Sphere.Safety;
|
||||||
using DysonNetwork.Sphere.Wallet.PaymentHandlers;
|
using DysonNetwork.Sphere.Wallet.PaymentHandlers;
|
||||||
using tusdotnet.Stores;
|
using tusdotnet.Stores;
|
||||||
@ -227,6 +228,7 @@ public static class ServiceCollectionExtensions
|
|||||||
services.AddScoped<WebFeedService>();
|
services.AddScoped<WebFeedService>();
|
||||||
services.AddScoped<AfdianPaymentHandler>();
|
services.AddScoped<AfdianPaymentHandler>();
|
||||||
services.AddScoped<SafetyService>();
|
services.AddScoped<SafetyService>();
|
||||||
|
services.AddScoped<DiscoveryService>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user