Add broadcast scheduling features: implement Show and Channel entities, enhance AppDbContext and DependencyInjection for broadcasting, and update API routing. Include migration for new database schema and update documentation for broadcast-related functionalities.

This commit is contained in:
Leonid Pershin
2026-07-24 08:57:08 +03:00
parent e15ecbdb29
commit 4fa9dae37f
86 changed files with 4094 additions and 15 deletions
@@ -2,6 +2,8 @@ using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Domain.Auth;
using TeleWave.Domain.Broadcast;
using TeleWave.Domain.Library;
using TeleWave.Domain.Media;
using TeleWave.Infrastructure.Identity;
@@ -17,6 +19,9 @@ public class AppDbContext(DbContextOptions<AppDbContext> options)
{
public DbSet<RefreshToken> RefreshTokens => Set<RefreshToken>();
public DbSet<MediaAsset> MediaAssets => Set<MediaAsset>();
public DbSet<Show> Shows => Set<Show>();
public DbSet<Channel> Channels => Set<Channel>();
public DbSet<ScheduleEntry> ScheduleEntries => Set<ScheduleEntry>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
@@ -0,0 +1,68 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using TeleWave.Domain.Broadcast;
namespace TeleWave.Infrastructure.Persistence.Configurations;
public class ChannelConfiguration : IEntityTypeConfiguration<Channel>
{
public void Configure(EntityTypeBuilder<Channel> builder)
{
builder.Property(x => x.Name).IsRequired().HasMaxLength(256);
builder.Property(x => x.Slug).IsRequired().HasMaxLength(128);
builder.HasIndex(x => x.Slug).IsUnique();
builder
.HasMany(x => x.Shows)
.WithOne()
.HasForeignKey(s => s.ChannelId)
.OnDelete(DeleteBehavior.Cascade);
builder.Navigation(x => x.Shows).UsePropertyAccessMode(PropertyAccessMode.Field);
builder
.HasMany(x => x.Ads)
.WithOne()
.HasForeignKey(a => a.ChannelId)
.OnDelete(DeleteBehavior.Cascade);
builder.Navigation(x => x.Ads).UsePropertyAccessMode(PropertyAccessMode.Field);
builder
.HasMany(x => x.Overrides)
.WithOne()
.HasForeignKey(o => o.ChannelId)
.OnDelete(DeleteBehavior.Cascade);
builder.Navigation(x => x.Overrides).UsePropertyAccessMode(PropertyAccessMode.Field);
}
}
public class ChannelShowConfiguration : IEntityTypeConfiguration<ChannelShow>
{
public void Configure(EntityTypeBuilder<ChannelShow> builder)
{
builder.HasIndex(x => new { x.ChannelId, x.ShowId });
}
}
public class ChannelAdConfiguration : IEntityTypeConfiguration<ChannelAd>
{
public void Configure(EntityTypeBuilder<ChannelAd> builder)
{
builder.HasIndex(x => new { x.ChannelId, x.Position });
}
}
public class ProgrammingOverrideConfiguration : IEntityTypeConfiguration<ProgrammingOverride>
{
public void Configure(EntityTypeBuilder<ProgrammingOverride> builder)
{
builder.HasIndex(x => new { x.ChannelId, x.StartsAtUtc, x.EndsAtUtc });
builder
.HasMany(x => x.Shows)
.WithOne()
.HasForeignKey(s => s.ProgrammingOverrideId)
.OnDelete(DeleteBehavior.Cascade);
builder.Navigation(x => x.Shows).UsePropertyAccessMode(PropertyAccessMode.Field);
}
}
@@ -0,0 +1,16 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using TeleWave.Domain.Broadcast;
namespace TeleWave.Infrastructure.Persistence.Configurations;
public class ScheduleEntryConfiguration : IEntityTypeConfiguration<ScheduleEntry>
{
public void Configure(EntityTypeBuilder<ScheduleEntry> builder)
{
// Основные запросы эфира/EPG — по каналу и времени.
builder.HasIndex(x => new { x.ChannelId, x.StartsAtUtc });
builder.HasIndex(x => new { x.ChannelId, x.EndsAtUtc });
builder.HasIndex(x => new { x.ChannelId, x.ShowId });
}
}
@@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using TeleWave.Domain.Library;
namespace TeleWave.Infrastructure.Persistence.Configurations;
public class ShowConfiguration : IEntityTypeConfiguration<Show>
{
public void Configure(EntityTypeBuilder<Show> builder)
{
builder.Property(x => x.Name).IsRequired().HasMaxLength(256);
builder.Property(x => x.Description).HasMaxLength(2048);
builder
.HasMany(x => x.Episodes)
.WithOne()
.HasForeignKey(e => e.ShowId)
.OnDelete(DeleteBehavior.Cascade);
builder.Navigation(x => x.Episodes).UsePropertyAccessMode(PropertyAccessMode.Field);
}
}
public class ShowEpisodeConfiguration : IEntityTypeConfiguration<ShowEpisode>
{
public void Configure(EntityTypeBuilder<ShowEpisode> builder)
{
builder.HasIndex(x => new { x.ShowId, x.Position });
builder.HasIndex(x => x.MediaAssetId);
}
}