Normalize line endings to LF via .gitattributes

Репозиторий хранил фронтенд в CRLF, а часть бэкенда — вперемешку, хотя CI и Docker-сборка
работают под Linux. Прибиваем LF атрибутом `* text=auto eol=lf` и разово нормализуем дерево,
чтобы форматтеры не переписывали файлы целиком на каждом прогоне.

Коммит чисто механический: изменений содержимого нет, только концы строк.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-07-27 01:37:33 +03:00
co-authored by Claude Opus 5
parent 9d1c6d2fc3
commit 0442056367
109 changed files with 13469 additions and 13459 deletions
@@ -1,96 +1,96 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using TeleWave.Application.Broadcast.Scheduling;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Programming.Planning;
namespace TeleWave.Infrastructure.Broadcast;
/// <summary>
/// Периодически достраивает расписание каждого включённого канала до горизонта. Расширение хвоста —
/// без удаления существующих записей, поэтому эфир не «дёргается».
/// </summary>
public sealed class SchedulingBackgroundService(
IServiceScopeFactory scopeFactory,
IOptions<SchedulerOptions> options,
ILogger<SchedulingBackgroundService> logger
) : BackgroundService
{
private readonly SchedulerOptions _options = options.Value;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// Небольшая задержка на старте — дать примениться миграциям/сидингу.
try
{
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
catch (OperationCanceledException)
{
return;
}
using var timer = new PeriodicTimer(
TimeSpan.FromMinutes(Math.Max(1, _options.TickMinutes))
);
do
{
try
{
await TickAsync(stoppingToken);
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
break;
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка тика планировщика");
}
} while (await timer.WaitForNextTickAsync(stoppingToken));
}
private async Task TickAsync(CancellationToken cancellationToken)
{
await using var scope = scopeFactory.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<IAppDbContext>();
var generator = scope.ServiceProvider.GetRequiredService<GridScheduleGenerator>();
// Эфир строит только шаблон сетки: канал без шаблона вещать не может и молча пропускается.
var channelIds = await db
.Channels.Where(c => c.IsEnabled && c.TemplateId != null)
.Select(c => c.Id)
.ToListAsync(cancellationToken);
var now = DateTimeOffset.UtcNow;
foreach (var channelId in channelIds)
{
var report = await generator.GenerateAsync(
channelId,
now,
rebuildFuture: false,
cancellationToken
);
if (report.Added > 0)
logger.LogInformation(
"Канал {ChannelId}: добавлено {Count} записей расписания",
channelId,
report.Added
);
foreach (var warning in report.Warnings)
logger.LogWarning(
"Канал {ChannelId}, слот {SlotId}: {Warning} — {Details}",
channelId,
warning.SlotId,
warning.Kind,
warning.Details
);
}
}
}
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using TeleWave.Application.Broadcast.Scheduling;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Programming.Planning;
namespace TeleWave.Infrastructure.Broadcast;
/// <summary>
/// Периодически достраивает расписание каждого включённого канала до горизонта. Расширение хвоста —
/// без удаления существующих записей, поэтому эфир не «дёргается».
/// </summary>
public sealed class SchedulingBackgroundService(
IServiceScopeFactory scopeFactory,
IOptions<SchedulerOptions> options,
ILogger<SchedulingBackgroundService> logger
) : BackgroundService
{
private readonly SchedulerOptions _options = options.Value;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// Небольшая задержка на старте — дать примениться миграциям/сидингу.
try
{
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
catch (OperationCanceledException)
{
return;
}
using var timer = new PeriodicTimer(
TimeSpan.FromMinutes(Math.Max(1, _options.TickMinutes))
);
do
{
try
{
await TickAsync(stoppingToken);
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
break;
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка тика планировщика");
}
} while (await timer.WaitForNextTickAsync(stoppingToken));
}
private async Task TickAsync(CancellationToken cancellationToken)
{
await using var scope = scopeFactory.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<IAppDbContext>();
var generator = scope.ServiceProvider.GetRequiredService<GridScheduleGenerator>();
// Эфир строит только шаблон сетки: канал без шаблона вещать не может и молча пропускается.
var channelIds = await db
.Channels.Where(c => c.IsEnabled && c.TemplateId != null)
.Select(c => c.Id)
.ToListAsync(cancellationToken);
var now = DateTimeOffset.UtcNow;
foreach (var channelId in channelIds)
{
var report = await generator.GenerateAsync(
channelId,
now,
rebuildFuture: false,
cancellationToken
);
if (report.Added > 0)
logger.LogInformation(
"Канал {ChannelId}: добавлено {Count} записей расписания",
channelId,
report.Added
);
foreach (var warning in report.Warnings)
logger.LogWarning(
"Канал {ChannelId}, слот {SlotId}: {Warning} — {Details}",
channelId,
warning.SlotId,
warning.Kind,
warning.Details
);
}
}
}
@@ -1,168 +1,168 @@
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using TeleWave.Application.Broadcast.Bumpers;
using TeleWave.Application.Broadcast.Scheduling;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Streaming;
using TeleWave.Domain.Broadcast.Scheduling;
using TeleWave.Infrastructure.Broadcast;
using TeleWave.Infrastructure.Identity;
using TeleWave.Infrastructure.Library;
using TeleWave.Infrastructure.Media;
using TeleWave.Infrastructure.Metadata;
using TeleWave.Infrastructure.Persistence;
using TeleWave.Infrastructure.Settings;
using TeleWave.Infrastructure.Streaming;
namespace TeleWave.Infrastructure;
/// <summary>
/// Регистрация сервисов инфраструктуры: EF Core (PostgreSQL), Identity/JWT-аутентификация.
/// </summary>
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration configuration
)
{
services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(
configuration["ConnectionStrings:Default"]
?? throw new InvalidOperationException(
"Строка подключения 'ConnectionStrings:Default' не сконфигурирована."
)
)
);
services.AddScoped<IAppDbContext>(sp => sp.GetRequiredService<AppDbContext>());
services
.AddIdentityCore<AppUser>(options =>
{
options.User.RequireUniqueEmail = false;
options.Password.RequiredLength = 8;
options.Password.RequireDigit = true;
options.Password.RequireUppercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.AllowedForNewUsers = true;
})
.AddRoles<AppRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();
services.Configure<JwtOptions>(configuration.GetSection(JwtOptions.SectionName));
services.Configure<AdminSeedOptions>(
configuration.GetSection(AdminSeedOptions.SectionName)
);
var jwtOptions =
configuration.GetSection(JwtOptions.SectionName).Get<JwtOptions>()
?? throw new InvalidOperationException("Секция конфигурации 'Jwt' не задана.");
// Fail-fast на подписывающем ключе: этот же ключ подписывает и JWT, и stream-токены
// (StreamTokenService), поэтому placeholder/короткий ключ из appsettings.json = полный обход
// авторизации (можно сфорджить admin-JWT). Лучше не стартовать вовсе, чем стартовать уязвимым.
// HMAC-SHA256 требует ключ не короче размера хеша (32 байта), иначе он ослаблен нулевым паддингом.
if (Encoding.UTF8.GetByteCount(jwtOptions.SigningKey) < 32)
throw new InvalidOperationException(
"Jwt:SigningKey должен быть не короче 32 байт. Задайте криптостойкий секрет через конфигурацию/переменную окружения Jwt__SigningKey."
);
if (jwtOptions.SigningKey.Contains("change-me", StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException(
"Jwt:SigningKey использует значение-заглушку из appsettings.json. Переопределите его криптостойким секретом (Jwt__SigningKey)."
);
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtOptions.Issuer,
ValidateAudience = true,
ValidAudience = jwtOptions.Audience,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtOptions.SigningKey)
),
ValidateLifetime = true,
ClockSkew = TimeSpan.FromSeconds(30),
};
});
services.AddAuthorization();
services.AddScoped<IIdentityService, IdentityService>();
services.AddScoped<IJwtTokenService, JwtTokenService>();
services.AddScoped<IRefreshTokenService, RefreshTokenService>();
services.AddScoped<IRoleService, RoleService>();
services.AddScoped<ICurrentUser, CurrentUser>();
services.AddScoped<ISiteSettings, SiteSettings>();
services.AddScoped<DbInitializer>();
services.AddScoped<GenreSeeder>();
AddMedia(services, configuration);
AddBroadcast(services, configuration);
AddMetadata(services, configuration);
return services;
}
/// <summary>Метаданные шоу/серий: провайдеры TMDb/OMDb, резолвер, локальное хранилище картинок.</summary>
private static void AddMetadata(IServiceCollection services, IConfiguration configuration)
{
services.Configure<MetadataOptions>(configuration.GetSection(MetadataOptions.SectionName));
services.AddHttpClient("metadata", client => client.Timeout = TimeSpan.FromSeconds(15));
services.AddSingleton<IMetadataProvider, TmdbMetadataProvider>();
services.AddSingleton<IMetadataProvider, OmdbMetadataProvider>();
services.AddSingleton<IMetadataProviderResolver, MetadataProviderResolver>();
}
/// <summary>Планировщик расписания: генератор, источник случайности и фоновый сервис горизонта.</summary>
private static void AddBroadcast(IServiceCollection services, IConfiguration configuration)
{
services.Configure<SchedulerOptions>(
configuration.GetSection(SchedulerOptions.SectionName)
);
services.Configure<StreamingOptions>(
configuration.GetSection(StreamingOptions.SectionName)
);
services.Configure<BumperOptions>(configuration.GetSection(BumperOptions.SectionName));
services.AddSingleton<IRandomSource, SystemRandomSource>();
services.AddSingleton<StreamTokenService>();
services.AddSingleton<IBumperRenderer, FfmpegBumperRenderer>();
services.AddHostedService<SchedulingBackgroundService>();
services.AddHostedService<MaintenanceBackgroundService>();
}
/// <summary>Хранилище медиа, обработка ffmpeg, очередь и фоновые сервисы (очередь + inbox-сканер).</summary>
private static void AddMedia(IServiceCollection services, IConfiguration configuration)
{
services.Configure<StorageOptions>(configuration.GetSection(StorageOptions.SectionName));
services.Configure<MediaOptions>(configuration.GetSection(MediaOptions.SectionName));
services.AddSingleton<MediaPathResolver>();
services.AddSingleton<IMediaStorage, FileSystemMediaStorage>();
services.AddSingleton<IBumperTemplateStorage, BumperTemplateStorage>();
services.AddSingleton<IImageStore, ImageStore>();
services.AddSingleton<IImageDownloader, ImageDownloader>();
services.AddSingleton<IAudioProbe, FfprobeAudioProbe>();
services.AddSingleton<IMediaProcessor, FfmpegMediaProcessor>();
services.AddSingleton<IMediaProcessingQueue, MediaProcessingQueue>();
services.AddSingleton<IBumperRenderQueue, BumperRenderQueue>();
services.AddHostedService<MediaProcessingBackgroundService>();
services.AddHostedService<InboxScannerBackgroundService>();
services.AddHostedService<BumperRenderBackgroundService>();
}
}
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using TeleWave.Application.Broadcast.Bumpers;
using TeleWave.Application.Broadcast.Scheduling;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Streaming;
using TeleWave.Domain.Broadcast.Scheduling;
using TeleWave.Infrastructure.Broadcast;
using TeleWave.Infrastructure.Identity;
using TeleWave.Infrastructure.Library;
using TeleWave.Infrastructure.Media;
using TeleWave.Infrastructure.Metadata;
using TeleWave.Infrastructure.Persistence;
using TeleWave.Infrastructure.Settings;
using TeleWave.Infrastructure.Streaming;
namespace TeleWave.Infrastructure;
/// <summary>
/// Регистрация сервисов инфраструктуры: EF Core (PostgreSQL), Identity/JWT-аутентификация.
/// </summary>
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration configuration
)
{
services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(
configuration["ConnectionStrings:Default"]
?? throw new InvalidOperationException(
"Строка подключения 'ConnectionStrings:Default' не сконфигурирована."
)
)
);
services.AddScoped<IAppDbContext>(sp => sp.GetRequiredService<AppDbContext>());
services
.AddIdentityCore<AppUser>(options =>
{
options.User.RequireUniqueEmail = false;
options.Password.RequiredLength = 8;
options.Password.RequireDigit = true;
options.Password.RequireUppercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.AllowedForNewUsers = true;
})
.AddRoles<AppRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();
services.Configure<JwtOptions>(configuration.GetSection(JwtOptions.SectionName));
services.Configure<AdminSeedOptions>(
configuration.GetSection(AdminSeedOptions.SectionName)
);
var jwtOptions =
configuration.GetSection(JwtOptions.SectionName).Get<JwtOptions>()
?? throw new InvalidOperationException("Секция конфигурации 'Jwt' не задана.");
// Fail-fast на подписывающем ключе: этот же ключ подписывает и JWT, и stream-токены
// (StreamTokenService), поэтому placeholder/короткий ключ из appsettings.json = полный обход
// авторизации (можно сфорджить admin-JWT). Лучше не стартовать вовсе, чем стартовать уязвимым.
// HMAC-SHA256 требует ключ не короче размера хеша (32 байта), иначе он ослаблен нулевым паддингом.
if (Encoding.UTF8.GetByteCount(jwtOptions.SigningKey) < 32)
throw new InvalidOperationException(
"Jwt:SigningKey должен быть не короче 32 байт. Задайте криптостойкий секрет через конфигурацию/переменную окружения Jwt__SigningKey."
);
if (jwtOptions.SigningKey.Contains("change-me", StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException(
"Jwt:SigningKey использует значение-заглушку из appsettings.json. Переопределите его криптостойким секретом (Jwt__SigningKey)."
);
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtOptions.Issuer,
ValidateAudience = true,
ValidAudience = jwtOptions.Audience,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtOptions.SigningKey)
),
ValidateLifetime = true,
ClockSkew = TimeSpan.FromSeconds(30),
};
});
services.AddAuthorization();
services.AddScoped<IIdentityService, IdentityService>();
services.AddScoped<IJwtTokenService, JwtTokenService>();
services.AddScoped<IRefreshTokenService, RefreshTokenService>();
services.AddScoped<IRoleService, RoleService>();
services.AddScoped<ICurrentUser, CurrentUser>();
services.AddScoped<ISiteSettings, SiteSettings>();
services.AddScoped<DbInitializer>();
services.AddScoped<GenreSeeder>();
AddMedia(services, configuration);
AddBroadcast(services, configuration);
AddMetadata(services, configuration);
return services;
}
/// <summary>Метаданные шоу/серий: провайдеры TMDb/OMDb, резолвер, локальное хранилище картинок.</summary>
private static void AddMetadata(IServiceCollection services, IConfiguration configuration)
{
services.Configure<MetadataOptions>(configuration.GetSection(MetadataOptions.SectionName));
services.AddHttpClient("metadata", client => client.Timeout = TimeSpan.FromSeconds(15));
services.AddSingleton<IMetadataProvider, TmdbMetadataProvider>();
services.AddSingleton<IMetadataProvider, OmdbMetadataProvider>();
services.AddSingleton<IMetadataProviderResolver, MetadataProviderResolver>();
}
/// <summary>Планировщик расписания: генератор, источник случайности и фоновый сервис горизонта.</summary>
private static void AddBroadcast(IServiceCollection services, IConfiguration configuration)
{
services.Configure<SchedulerOptions>(
configuration.GetSection(SchedulerOptions.SectionName)
);
services.Configure<StreamingOptions>(
configuration.GetSection(StreamingOptions.SectionName)
);
services.Configure<BumperOptions>(configuration.GetSection(BumperOptions.SectionName));
services.AddSingleton<IRandomSource, SystemRandomSource>();
services.AddSingleton<StreamTokenService>();
services.AddSingleton<IBumperRenderer, FfmpegBumperRenderer>();
services.AddHostedService<SchedulingBackgroundService>();
services.AddHostedService<MaintenanceBackgroundService>();
}
/// <summary>Хранилище медиа, обработка ffmpeg, очередь и фоновые сервисы (очередь + inbox-сканер).</summary>
private static void AddMedia(IServiceCollection services, IConfiguration configuration)
{
services.Configure<StorageOptions>(configuration.GetSection(StorageOptions.SectionName));
services.Configure<MediaOptions>(configuration.GetSection(MediaOptions.SectionName));
services.AddSingleton<MediaPathResolver>();
services.AddSingleton<IMediaStorage, FileSystemMediaStorage>();
services.AddSingleton<IBumperTemplateStorage, BumperTemplateStorage>();
services.AddSingleton<IImageStore, ImageStore>();
services.AddSingleton<IImageDownloader, ImageDownloader>();
services.AddSingleton<IAudioProbe, FfprobeAudioProbe>();
services.AddSingleton<IMediaProcessor, FfmpegMediaProcessor>();
services.AddSingleton<IMediaProcessingQueue, MediaProcessingQueue>();
services.AddSingleton<IBumperRenderQueue, BumperRenderQueue>();
services.AddHostedService<MediaProcessingBackgroundService>();
services.AddHostedService<InboxScannerBackgroundService>();
services.AddHostedService<BumperRenderBackgroundService>();
}
}
@@ -1,171 +1,171 @@
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Media;
using TeleWave.Domain.Media;
namespace TeleWave.Infrastructure.Media;
/// <summary>Файловая реализация <see cref="IMediaStorage"/> поверх <see cref="MediaPathResolver"/>.</summary>
public sealed class FileSystemMediaStorage(MediaPathResolver paths) : IMediaStorage
{
private const int CopyBufferSize = 1024 * 1024;
public long GetAvailableFreeSpaceBytes()
{
try
{
return new DriveInfo(paths.AssetsDir).AvailableFreeSpace;
}
catch (Exception ex) when (ex is ArgumentException or IOException)
{
// Не блокируем загрузку, если ФС не отдаёт метрику (например экзотическая точка монтирования).
return long.MaxValue;
}
}
public async Task<string> SaveUploadAsync(
Stream content,
string extension,
CancellationToken cancellationToken
)
{
Directory.CreateDirectory(paths.UploadsDir);
var token = Guid.NewGuid().ToString("N") + extension.ToLowerInvariant();
var path = paths.UploadPath(token);
await using var file = new FileStream(
path,
FileMode.CreateNew,
FileAccess.Write,
FileShare.None,
CopyBufferSize,
useAsync: true
);
await content.CopyToAsync(file, CopyBufferSize, cancellationToken);
return token;
}
public Task DeleteUploadAsync(string uploadToken, CancellationToken cancellationToken)
{
var path = paths.UploadPath(uploadToken);
if (File.Exists(path))
File.Delete(path);
return Task.CompletedTask;
}
public IReadOnlyList<IMediaStorage.ManualInboxFile> ListManualInbox(int max)
{
if (!Directory.Exists(paths.ManualDir))
return [];
return Directory
.EnumerateFiles(paths.ManualDir, "*", SearchOption.AllDirectories)
.Take(Math.Max(1, max))
.Select(path => new FileInfo(path))
.Where(file => file.Exists)
.Select(file => new IMediaStorage.ManualInboxFile(
// Разделитель нормализуем: путь уезжает в URL и обратно приходит строкой запроса.
Path.GetRelativePath(paths.ManualDir, file.FullName).Replace('\\', '/'),
file.Name,
file.Length
))
.OrderBy(f => f.RelativePath, StringComparer.OrdinalIgnoreCase)
.ToList();
}
public Task CleanupManualLeftoversAsync(
string relativePath,
CancellationToken cancellationToken
)
{
var path = paths.ManualPath(relativePath);
var directory = Path.GetDirectoryName(path);
if (directory is null || !Directory.Exists(directory))
return Task.CompletedTask;
// Спутник — файл, чьё имя начинается с имени забранного (без расширения) и точки:
// так ловятся и «Серия.srt», и «Серия.ru.srt». Видеофайлы исключены намеренно —
// «Серия.Extended.mkv» это не мусор, а другой материал.
// Отбор — своим сравнением, а не маской поиска: в имени файла на Linux законно встречается
// «*», и маска захватила бы чужие файлы. Код удаляет — он обязан быть буквальным.
var prefix = Path.GetFileNameWithoutExtension(path) + ".";
foreach (var sibling in Directory.EnumerateFiles(directory))
{
var name = Path.GetFileName(sibling);
if (!name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
continue;
if (MediaFormats.IsAllowed(name))
continue;
try
{
File.Delete(sibling);
}
catch (IOException)
{
// Файл занят или уже удалён — не повод валить импорт целиком.
}
}
// Опустевший подкаталог тоже мусор. Корень manual/ не трогаем: он нужен всегда.
if (
!string.Equals(directory, paths.ManualDir, StringComparison.Ordinal)
&& !Directory.EnumerateFileSystemEntries(directory).Any()
)
{
try
{
Directory.Delete(directory);
}
catch (IOException)
{
// Каталог занят — оставим как есть.
}
}
return Task.CompletedTask;
}
public Task PromoteToOriginalAsync(
MediaSource source,
string sourceToken,
Guid assetId,
string extension,
CancellationToken cancellationToken
)
{
var sourcePath = source switch
{
MediaSource.Inbox => paths.InboxPath(sourceToken),
MediaSource.ManualInbox => paths.ManualPath(sourceToken),
_ => paths.UploadPath(sourceToken),
};
if (!File.Exists(sourcePath))
throw new FileNotFoundException("Исходный файл не найден в хранилище.", sourcePath);
Directory.CreateDirectory(paths.OriginalsDir);
var destination = paths.OriginalPath(assetId, extension);
File.Move(sourcePath, destination, overwrite: true);
return Task.CompletedTask;
}
public Task DeleteAssetArtifactsAsync(
Guid assetId,
string extension,
CancellationToken cancellationToken
) =>
// Каталог сегментов удаляется рекурсивно (может быть много .ts) — офлоадим с вызывающего потока
// (запрос/фоновый сервис), чтобы не блокировать его на время файлового I/O.
Task.Run(
() =>
{
var original = paths.OriginalPath(assetId, extension);
if (File.Exists(original))
File.Delete(original);
var assetDir = paths.AssetDir(assetId);
if (Directory.Exists(assetDir))
Directory.Delete(assetDir, recursive: true);
},
cancellationToken
);
}
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Media;
using TeleWave.Domain.Media;
namespace TeleWave.Infrastructure.Media;
/// <summary>Файловая реализация <see cref="IMediaStorage"/> поверх <see cref="MediaPathResolver"/>.</summary>
public sealed class FileSystemMediaStorage(MediaPathResolver paths) : IMediaStorage
{
private const int CopyBufferSize = 1024 * 1024;
public long GetAvailableFreeSpaceBytes()
{
try
{
return new DriveInfo(paths.AssetsDir).AvailableFreeSpace;
}
catch (Exception ex) when (ex is ArgumentException or IOException)
{
// Не блокируем загрузку, если ФС не отдаёт метрику (например экзотическая точка монтирования).
return long.MaxValue;
}
}
public async Task<string> SaveUploadAsync(
Stream content,
string extension,
CancellationToken cancellationToken
)
{
Directory.CreateDirectory(paths.UploadsDir);
var token = Guid.NewGuid().ToString("N") + extension.ToLowerInvariant();
var path = paths.UploadPath(token);
await using var file = new FileStream(
path,
FileMode.CreateNew,
FileAccess.Write,
FileShare.None,
CopyBufferSize,
useAsync: true
);
await content.CopyToAsync(file, CopyBufferSize, cancellationToken);
return token;
}
public Task DeleteUploadAsync(string uploadToken, CancellationToken cancellationToken)
{
var path = paths.UploadPath(uploadToken);
if (File.Exists(path))
File.Delete(path);
return Task.CompletedTask;
}
public IReadOnlyList<IMediaStorage.ManualInboxFile> ListManualInbox(int max)
{
if (!Directory.Exists(paths.ManualDir))
return [];
return Directory
.EnumerateFiles(paths.ManualDir, "*", SearchOption.AllDirectories)
.Take(Math.Max(1, max))
.Select(path => new FileInfo(path))
.Where(file => file.Exists)
.Select(file => new IMediaStorage.ManualInboxFile(
// Разделитель нормализуем: путь уезжает в URL и обратно приходит строкой запроса.
Path.GetRelativePath(paths.ManualDir, file.FullName).Replace('\\', '/'),
file.Name,
file.Length
))
.OrderBy(f => f.RelativePath, StringComparer.OrdinalIgnoreCase)
.ToList();
}
public Task CleanupManualLeftoversAsync(
string relativePath,
CancellationToken cancellationToken
)
{
var path = paths.ManualPath(relativePath);
var directory = Path.GetDirectoryName(path);
if (directory is null || !Directory.Exists(directory))
return Task.CompletedTask;
// Спутник — файл, чьё имя начинается с имени забранного (без расширения) и точки:
// так ловятся и «Серия.srt», и «Серия.ru.srt». Видеофайлы исключены намеренно —
// «Серия.Extended.mkv» это не мусор, а другой материал.
// Отбор — своим сравнением, а не маской поиска: в имени файла на Linux законно встречается
// «*», и маска захватила бы чужие файлы. Код удаляет — он обязан быть буквальным.
var prefix = Path.GetFileNameWithoutExtension(path) + ".";
foreach (var sibling in Directory.EnumerateFiles(directory))
{
var name = Path.GetFileName(sibling);
if (!name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
continue;
if (MediaFormats.IsAllowed(name))
continue;
try
{
File.Delete(sibling);
}
catch (IOException)
{
// Файл занят или уже удалён — не повод валить импорт целиком.
}
}
// Опустевший подкаталог тоже мусор. Корень manual/ не трогаем: он нужен всегда.
if (
!string.Equals(directory, paths.ManualDir, StringComparison.Ordinal)
&& !Directory.EnumerateFileSystemEntries(directory).Any()
)
{
try
{
Directory.Delete(directory);
}
catch (IOException)
{
// Каталог занят — оставим как есть.
}
}
return Task.CompletedTask;
}
public Task PromoteToOriginalAsync(
MediaSource source,
string sourceToken,
Guid assetId,
string extension,
CancellationToken cancellationToken
)
{
var sourcePath = source switch
{
MediaSource.Inbox => paths.InboxPath(sourceToken),
MediaSource.ManualInbox => paths.ManualPath(sourceToken),
_ => paths.UploadPath(sourceToken),
};
if (!File.Exists(sourcePath))
throw new FileNotFoundException("Исходный файл не найден в хранилище.", sourcePath);
Directory.CreateDirectory(paths.OriginalsDir);
var destination = paths.OriginalPath(assetId, extension);
File.Move(sourcePath, destination, overwrite: true);
return Task.CompletedTask;
}
public Task DeleteAssetArtifactsAsync(
Guid assetId,
string extension,
CancellationToken cancellationToken
) =>
// Каталог сегментов удаляется рекурсивно (может быть много .ts) — офлоадим с вызывающего потока
// (запрос/фоновый сервис), чтобы не блокировать его на время файлового I/O.
Task.Run(
() =>
{
var original = paths.OriginalPath(assetId, extension);
if (File.Exists(original))
File.Delete(original);
var assetDir = paths.AssetDir(assetId);
if (Directory.Exists(assetDir))
Directory.Delete(assetDir, recursive: true);
},
cancellationToken
);
}
@@ -1,111 +1,111 @@
using Microsoft.Extensions.Options;
namespace TeleWave.Infrastructure.Media;
/// <summary>
/// Единая точка резолва путей хранилища + защита от path traversal. Любой путь, собранный из
/// внешних данных (имя загруженного файла, имя из inbox/), проверяется на нахождение внутри корня.
/// </summary>
public sealed class MediaPathResolver
{
private readonly string _root;
public MediaPathResolver(IOptions<StorageOptions> options)
{
_root = Path.GetFullPath(options.Value.RootPath);
InboxDir = Path.Combine(_root, "inbox");
ManualDir = Path.Combine(_root, "manual");
UploadsDir = Path.Combine(_root, "uploads");
OriginalsDir = Path.Combine(_root, "originals");
AssetsDir = Path.Combine(_root, "assets");
BumpersDir = Path.Combine(_root, "bumpers");
ImagesDir = Path.Combine(_root, "images");
}
public string InboxDir { get; }
/// <summary>Ручной inbox: сканером не разбирается, файлы забирает админ из UI сразу в шоу.</summary>
public string ManualDir { get; }
public string UploadsDir { get; }
public string OriginalsDir { get; }
public string AssetsDir { get; }
/// <summary>Сырые файлы шаблонов заставок (фон/музыка) по каналам — не режутся на HLS.</summary>
public string BumpersDir { get; }
/// <summary>Общий реестр изображений (галерея): файлы images/{imageId}{ext}.</summary>
public string ImagesDir { get; }
public void EnsureDirectories()
{
Directory.CreateDirectory(InboxDir);
Directory.CreateDirectory(ManualDir);
Directory.CreateDirectory(UploadsDir);
Directory.CreateDirectory(OriginalsDir);
Directory.CreateDirectory(AssetsDir);
Directory.CreateDirectory(BumpersDir);
Directory.CreateDirectory(ImagesDir);
}
public string BumperTemplateDir(Guid templateId) =>
EnsureWithinRoot(Path.Combine(BumpersDir, templateId.ToString("N")));
/// <summary>Путь к файлу блока заставки (kind — «audio»/«background», extension — с точкой).</summary>
public string BumperTemplateFilePath(Guid templateId, string kind, string extension) =>
EnsureWithinRoot(Path.Combine(BumpersDir, templateId.ToString("N"), kind + extension));
/// <summary>Путь к файлу изображения общего реестра (extension — с точкой).</summary>
public string ImagePath(Guid imageId, string extension) =>
EnsureWithinRoot(Path.Combine(ImagesDir, imageId.ToString("N") + extension));
public string OriginalPath(Guid assetId, string extension) =>
EnsureWithinRoot(Path.Combine(OriginalsDir, assetId.ToString("N") + extension));
public string AssetDir(Guid assetId) =>
EnsureWithinRoot(Path.Combine(AssetsDir, assetId.ToString("N")));
public static string AssetRelativePath(Guid assetId) => $"assets/{assetId:N}";
/// <summary>Путь к файлу сегмента внутри каталога ассета (имя файла проверяется на traversal).</summary>
public string SegmentPath(Guid assetId, string fileName)
{
var assetDir = AssetDir(assetId);
return EnsureWithin(assetDir, Path.Combine(assetDir, fileName));
}
/// <summary>Резолвит имя файла внутри uploads/ (токен загрузки), проверяя выход за пределы каталога.</summary>
public string UploadPath(string token) =>
EnsureWithin(UploadsDir, Path.Combine(UploadsDir, token));
/// <summary>Резолвит имя файла внутри inbox/, проверяя выход за пределы каталога.</summary>
public string InboxPath(string fileName) =>
EnsureWithin(InboxDir, Path.Combine(InboxDir, fileName));
/// <summary>
/// Резолвит путь внутри manual/. Путь относительный и может содержать подкаталоги — качалки
/// раскладывают файлы по папкам, — поэтому проверка на выход за пределы каталога здесь
/// обязательна: строка приходит из запроса.
/// </summary>
public string ManualPath(string relativePath) =>
EnsureWithin(ManualDir, Path.Combine(ManualDir, relativePath));
private string EnsureWithinRoot(string candidate) => EnsureWithin(_root, candidate);
private static string EnsureWithin(string baseDir, string candidate)
{
var full = Path.GetFullPath(candidate);
var normalizedBase = baseDir.EndsWith(Path.DirectorySeparatorChar)
? baseDir
: baseDir + Path.DirectorySeparatorChar;
if (
!full.StartsWith(normalizedBase, StringComparison.Ordinal)
&& !string.Equals(full, baseDir, StringComparison.Ordinal)
)
throw new UnauthorizedAccessException(
$"Путь '{candidate}' выходит за пределы каталога хранилища."
);
return full;
}
}
using Microsoft.Extensions.Options;
namespace TeleWave.Infrastructure.Media;
/// <summary>
/// Единая точка резолва путей хранилища + защита от path traversal. Любой путь, собранный из
/// внешних данных (имя загруженного файла, имя из inbox/), проверяется на нахождение внутри корня.
/// </summary>
public sealed class MediaPathResolver
{
private readonly string _root;
public MediaPathResolver(IOptions<StorageOptions> options)
{
_root = Path.GetFullPath(options.Value.RootPath);
InboxDir = Path.Combine(_root, "inbox");
ManualDir = Path.Combine(_root, "manual");
UploadsDir = Path.Combine(_root, "uploads");
OriginalsDir = Path.Combine(_root, "originals");
AssetsDir = Path.Combine(_root, "assets");
BumpersDir = Path.Combine(_root, "bumpers");
ImagesDir = Path.Combine(_root, "images");
}
public string InboxDir { get; }
/// <summary>Ручной inbox: сканером не разбирается, файлы забирает админ из UI сразу в шоу.</summary>
public string ManualDir { get; }
public string UploadsDir { get; }
public string OriginalsDir { get; }
public string AssetsDir { get; }
/// <summary>Сырые файлы шаблонов заставок (фон/музыка) по каналам — не режутся на HLS.</summary>
public string BumpersDir { get; }
/// <summary>Общий реестр изображений (галерея): файлы images/{imageId}{ext}.</summary>
public string ImagesDir { get; }
public void EnsureDirectories()
{
Directory.CreateDirectory(InboxDir);
Directory.CreateDirectory(ManualDir);
Directory.CreateDirectory(UploadsDir);
Directory.CreateDirectory(OriginalsDir);
Directory.CreateDirectory(AssetsDir);
Directory.CreateDirectory(BumpersDir);
Directory.CreateDirectory(ImagesDir);
}
public string BumperTemplateDir(Guid templateId) =>
EnsureWithinRoot(Path.Combine(BumpersDir, templateId.ToString("N")));
/// <summary>Путь к файлу блока заставки (kind — «audio»/«background», extension — с точкой).</summary>
public string BumperTemplateFilePath(Guid templateId, string kind, string extension) =>
EnsureWithinRoot(Path.Combine(BumpersDir, templateId.ToString("N"), kind + extension));
/// <summary>Путь к файлу изображения общего реестра (extension — с точкой).</summary>
public string ImagePath(Guid imageId, string extension) =>
EnsureWithinRoot(Path.Combine(ImagesDir, imageId.ToString("N") + extension));
public string OriginalPath(Guid assetId, string extension) =>
EnsureWithinRoot(Path.Combine(OriginalsDir, assetId.ToString("N") + extension));
public string AssetDir(Guid assetId) =>
EnsureWithinRoot(Path.Combine(AssetsDir, assetId.ToString("N")));
public static string AssetRelativePath(Guid assetId) => $"assets/{assetId:N}";
/// <summary>Путь к файлу сегмента внутри каталога ассета (имя файла проверяется на traversal).</summary>
public string SegmentPath(Guid assetId, string fileName)
{
var assetDir = AssetDir(assetId);
return EnsureWithin(assetDir, Path.Combine(assetDir, fileName));
}
/// <summary>Резолвит имя файла внутри uploads/ (токен загрузки), проверяя выход за пределы каталога.</summary>
public string UploadPath(string token) =>
EnsureWithin(UploadsDir, Path.Combine(UploadsDir, token));
/// <summary>Резолвит имя файла внутри inbox/, проверяя выход за пределы каталога.</summary>
public string InboxPath(string fileName) =>
EnsureWithin(InboxDir, Path.Combine(InboxDir, fileName));
/// <summary>
/// Резолвит путь внутри manual/. Путь относительный и может содержать подкаталоги — качалки
/// раскладывают файлы по папкам, — поэтому проверка на выход за пределы каталога здесь
/// обязательна: строка приходит из запроса.
/// </summary>
public string ManualPath(string relativePath) =>
EnsureWithin(ManualDir, Path.Combine(ManualDir, relativePath));
private string EnsureWithinRoot(string candidate) => EnsureWithin(_root, candidate);
private static string EnsureWithin(string baseDir, string candidate)
{
var full = Path.GetFullPath(candidate);
var normalizedBase = baseDir.EndsWith(Path.DirectorySeparatorChar)
? baseDir
: baseDir + Path.DirectorySeparatorChar;
if (
!full.StartsWith(normalizedBase, StringComparison.Ordinal)
&& !string.Equals(full, baseDir, StringComparison.Ordinal)
)
throw new UnauthorizedAccessException(
$"Путь '{candidate}' выходит за пределы каталога хранилища."
);
return full;
}
}
@@ -1,330 +1,330 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
IsSystem = table.Column<bool>(type: "boolean", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
NormalizedName = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
IsBlocked = table.Column<bool>(type: "boolean", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
UserName = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
NormalizedUserName = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
Email = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
NormalizedEmail = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PasswordHash = table.Column<string>(type: "text", nullable: true),
SecurityStamp = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
PhoneNumber = table.Column<string>(type: "text", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "RefreshTokens",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
TokenHash = table.Column<string>(type: "text", nullable: false),
ExpiresAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
RevokedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
ReplacedByTokenHash = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_RefreshTokens", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table
.Column<int>(type: "integer", nullable: false)
.Annotation(
"Npgsql:ValueGenerationStrategy",
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn
),
RoleId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table
.Column<int>(type: "integer", nullable: false)
.Annotation(
"Npgsql:ValueGenerationStrategy",
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn
),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
},
constraints: table =>
{
table.PrimaryKey(
"PK_AspNetUserLogins",
x => new { x.LoginProvider, x.ProviderKey }
);
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
RoleId = table.Column<Guid>(type: "uuid", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
LoginProvider = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Value = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey(
"PK_AspNetUserTokens",
x => new
{
x.UserId,
x.LoginProvider,
x.Name,
}
);
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId"
);
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId"
);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId"
);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId"
);
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail"
);
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_RefreshTokens_TokenHash",
table: "RefreshTokens",
column: "TokenHash",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_RefreshTokens_UserId",
table: "RefreshTokens",
column: "UserId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "AspNetRoleClaims");
migrationBuilder.DropTable(name: "AspNetUserClaims");
migrationBuilder.DropTable(name: "AspNetUserLogins");
migrationBuilder.DropTable(name: "AspNetUserRoles");
migrationBuilder.DropTable(name: "AspNetUserTokens");
migrationBuilder.DropTable(name: "RefreshTokens");
migrationBuilder.DropTable(name: "AspNetRoles");
migrationBuilder.DropTable(name: "AspNetUsers");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
IsSystem = table.Column<bool>(type: "boolean", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
NormalizedName = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
IsBlocked = table.Column<bool>(type: "boolean", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
UserName = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
NormalizedUserName = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
Email = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
NormalizedEmail = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PasswordHash = table.Column<string>(type: "text", nullable: true),
SecurityStamp = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
PhoneNumber = table.Column<string>(type: "text", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "RefreshTokens",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
TokenHash = table.Column<string>(type: "text", nullable: false),
ExpiresAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
RevokedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
ReplacedByTokenHash = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_RefreshTokens", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table
.Column<int>(type: "integer", nullable: false)
.Annotation(
"Npgsql:ValueGenerationStrategy",
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn
),
RoleId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table
.Column<int>(type: "integer", nullable: false)
.Annotation(
"Npgsql:ValueGenerationStrategy",
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn
),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
},
constraints: table =>
{
table.PrimaryKey(
"PK_AspNetUserLogins",
x => new { x.LoginProvider, x.ProviderKey }
);
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
RoleId = table.Column<Guid>(type: "uuid", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
LoginProvider = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Value = table.Column<string>(type: "text", nullable: true),
},
constraints: table =>
{
table.PrimaryKey(
"PK_AspNetUserTokens",
x => new
{
x.UserId,
x.LoginProvider,
x.Name,
}
);
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId"
);
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId"
);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId"
);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId"
);
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail"
);
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_RefreshTokens_TokenHash",
table: "RefreshTokens",
column: "TokenHash",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_RefreshTokens_UserId",
table: "RefreshTokens",
column: "UserId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "AspNetRoleClaims");
migrationBuilder.DropTable(name: "AspNetUserClaims");
migrationBuilder.DropTable(name: "AspNetUserLogins");
migrationBuilder.DropTable(name: "AspNetUserRoles");
migrationBuilder.DropTable(name: "AspNetUserTokens");
migrationBuilder.DropTable(name: "RefreshTokens");
migrationBuilder.DropTable(name: "AspNetRoles");
migrationBuilder.DropTable(name: "AspNetUsers");
}
}
}
@@ -1,90 +1,90 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddMediaAssets : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "MediaAssets",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
OriginalFileName = table.Column<string>(
type: "character varying(512)",
maxLength: 512,
nullable: false
),
OriginalExtension = table.Column<string>(
type: "character varying(16)",
maxLength: 16,
nullable: false
),
Source = table.Column<int>(type: "integer", nullable: false),
Status = table.Column<int>(type: "integer", nullable: false),
Duration = table.Column<TimeSpan>(type: "interval", nullable: true),
SegmentSeconds = table.Column<int>(type: "integer", nullable: true),
SegmentCount = table.Column<int>(type: "integer", nullable: true),
Width = table.Column<int>(type: "integer", nullable: true),
Height = table.Column<int>(type: "integer", nullable: true),
VideoCodec = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: true
),
AudioCodec = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: true
),
RelativePath = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
ErrorMessage = table.Column<string>(
type: "character varying(2048)",
maxLength: 2048,
nullable: true
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
UpdatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_MediaAssets", x => x.Id);
}
);
migrationBuilder.CreateIndex(
name: "IX_MediaAssets_CreatedAt",
table: "MediaAssets",
column: "CreatedAt"
);
migrationBuilder.CreateIndex(
name: "IX_MediaAssets_Status",
table: "MediaAssets",
column: "Status"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "MediaAssets");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddMediaAssets : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "MediaAssets",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
OriginalFileName = table.Column<string>(
type: "character varying(512)",
maxLength: 512,
nullable: false
),
OriginalExtension = table.Column<string>(
type: "character varying(16)",
maxLength: 16,
nullable: false
),
Source = table.Column<int>(type: "integer", nullable: false),
Status = table.Column<int>(type: "integer", nullable: false),
Duration = table.Column<TimeSpan>(type: "interval", nullable: true),
SegmentSeconds = table.Column<int>(type: "integer", nullable: true),
SegmentCount = table.Column<int>(type: "integer", nullable: true),
Width = table.Column<int>(type: "integer", nullable: true),
Height = table.Column<int>(type: "integer", nullable: true),
VideoCodec = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: true
),
AudioCodec = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: true
),
RelativePath = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: true
),
ErrorMessage = table.Column<string>(
type: "character varying(2048)",
maxLength: 2048,
nullable: true
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
UpdatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_MediaAssets", x => x.Id);
}
);
migrationBuilder.CreateIndex(
name: "IX_MediaAssets_CreatedAt",
table: "MediaAssets",
column: "CreatedAt"
);
migrationBuilder.CreateIndex(
name: "IX_MediaAssets_Status",
table: "MediaAssets",
column: "Status"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "MediaAssets");
}
}
}
@@ -1,308 +1,308 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddBroadcastAndLibrary : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Channels",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Slug = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
EpochUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
AdInsertion = table.Column<int>(type: "integer", nullable: false),
AdsPerBreak = table.Column<int>(type: "integer", nullable: false),
FillerAssetId = table.Column<Guid>(type: "uuid", nullable: true),
NextAdIndex = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Channels", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "ScheduleEntries",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Kind = table.Column<int>(type: "integer", nullable: false),
StartsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
EndsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
ShowId = table.Column<Guid>(type: "uuid", nullable: true),
EpisodeIndex = table.Column<int>(type: "integer", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_ScheduleEntries", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "Shows",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Description = table.Column<string>(
type: "character varying(2048)",
maxLength: 2048,
nullable: true
),
Kind = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Shows", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "ChannelAd",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelAd", x => x.Id);
table.ForeignKey(
name: "FK_ChannelAd_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ChannelShow",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
BlockMode = table.Column<int>(type: "integer", nullable: false),
BlockValue = table.Column<int>(type: "integer", nullable: false),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
NextEpisodeIndex = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelShow", x => x.Id);
table.ForeignKey(
name: "FK_ChannelShow_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ProgrammingOverride",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
Mode = table.Column<int>(type: "integer", nullable: false),
StartsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
EndsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_ProgrammingOverride", x => x.Id);
table.ForeignKey(
name: "FK_ProgrammingOverride_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ShowEpisode",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_ShowEpisode", x => x.Id);
table.ForeignKey(
name: "FK_ShowEpisode_Shows_ShowId",
column: x => x.ShowId,
principalTable: "Shows",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "OverrideShow",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ProgrammingOverrideId = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_OverrideShow", x => x.Id);
table.ForeignKey(
name: "FK_OverrideShow_ProgrammingOverride_ProgrammingOverrideId",
column: x => x.ProgrammingOverrideId,
principalTable: "ProgrammingOverride",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelAd_ChannelId_Position",
table: "ChannelAd",
columns: new[] { "ChannelId", "Position" }
);
migrationBuilder.CreateIndex(
name: "IX_Channels_Slug",
table: "Channels",
column: "Slug",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_ChannelShow_ChannelId_ShowId",
table: "ChannelShow",
columns: new[] { "ChannelId", "ShowId" }
);
migrationBuilder.CreateIndex(
name: "IX_OverrideShow_ProgrammingOverrideId",
table: "OverrideShow",
column: "ProgrammingOverrideId"
);
migrationBuilder.CreateIndex(
name: "IX_ProgrammingOverride_ChannelId_StartsAtUtc_EndsAtUtc",
table: "ProgrammingOverride",
columns: new[] { "ChannelId", "StartsAtUtc", "EndsAtUtc" }
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_EndsAtUtc",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "EndsAtUtc" }
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "ShowId" }
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_StartsAtUtc",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "StartsAtUtc" }
);
migrationBuilder.CreateIndex(
name: "IX_ShowEpisode_MediaAssetId",
table: "ShowEpisode",
column: "MediaAssetId"
);
migrationBuilder.CreateIndex(
name: "IX_ShowEpisode_ShowId_Position",
table: "ShowEpisode",
columns: new[] { "ShowId", "Position" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelAd");
migrationBuilder.DropTable(name: "ChannelShow");
migrationBuilder.DropTable(name: "OverrideShow");
migrationBuilder.DropTable(name: "ScheduleEntries");
migrationBuilder.DropTable(name: "ShowEpisode");
migrationBuilder.DropTable(name: "ProgrammingOverride");
migrationBuilder.DropTable(name: "Shows");
migrationBuilder.DropTable(name: "Channels");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddBroadcastAndLibrary : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Channels",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Slug = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
EpochUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
AdInsertion = table.Column<int>(type: "integer", nullable: false),
AdsPerBreak = table.Column<int>(type: "integer", nullable: false),
FillerAssetId = table.Column<Guid>(type: "uuid", nullable: true),
NextAdIndex = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Channels", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "ScheduleEntries",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Kind = table.Column<int>(type: "integer", nullable: false),
StartsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
EndsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
ShowId = table.Column<Guid>(type: "uuid", nullable: true),
EpisodeIndex = table.Column<int>(type: "integer", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_ScheduleEntries", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "Shows",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Description = table.Column<string>(
type: "character varying(2048)",
maxLength: 2048,
nullable: true
),
Kind = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Shows", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "ChannelAd",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelAd", x => x.Id);
table.ForeignKey(
name: "FK_ChannelAd_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ChannelShow",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
BlockMode = table.Column<int>(type: "integer", nullable: false),
BlockValue = table.Column<int>(type: "integer", nullable: false),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
NextEpisodeIndex = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelShow", x => x.Id);
table.ForeignKey(
name: "FK_ChannelShow_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ProgrammingOverride",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
Mode = table.Column<int>(type: "integer", nullable: false),
StartsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
EndsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_ProgrammingOverride", x => x.Id);
table.ForeignKey(
name: "FK_ProgrammingOverride_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ShowEpisode",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_ShowEpisode", x => x.Id);
table.ForeignKey(
name: "FK_ShowEpisode_Shows_ShowId",
column: x => x.ShowId,
principalTable: "Shows",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "OverrideShow",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ProgrammingOverrideId = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_OverrideShow", x => x.Id);
table.ForeignKey(
name: "FK_OverrideShow_ProgrammingOverride_ProgrammingOverrideId",
column: x => x.ProgrammingOverrideId,
principalTable: "ProgrammingOverride",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelAd_ChannelId_Position",
table: "ChannelAd",
columns: new[] { "ChannelId", "Position" }
);
migrationBuilder.CreateIndex(
name: "IX_Channels_Slug",
table: "Channels",
column: "Slug",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_ChannelShow_ChannelId_ShowId",
table: "ChannelShow",
columns: new[] { "ChannelId", "ShowId" }
);
migrationBuilder.CreateIndex(
name: "IX_OverrideShow_ProgrammingOverrideId",
table: "OverrideShow",
column: "ProgrammingOverrideId"
);
migrationBuilder.CreateIndex(
name: "IX_ProgrammingOverride_ChannelId_StartsAtUtc_EndsAtUtc",
table: "ProgrammingOverride",
columns: new[] { "ChannelId", "StartsAtUtc", "EndsAtUtc" }
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_EndsAtUtc",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "EndsAtUtc" }
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "ShowId" }
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_StartsAtUtc",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "StartsAtUtc" }
);
migrationBuilder.CreateIndex(
name: "IX_ShowEpisode_MediaAssetId",
table: "ShowEpisode",
column: "MediaAssetId"
);
migrationBuilder.CreateIndex(
name: "IX_ShowEpisode_ShowId_Position",
table: "ShowEpisode",
columns: new[] { "ShowId", "Position" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelAd");
migrationBuilder.DropTable(name: "ChannelShow");
migrationBuilder.DropTable(name: "OverrideShow");
migrationBuilder.DropTable(name: "ScheduleEntries");
migrationBuilder.DropTable(name: "ShowEpisode");
migrationBuilder.DropTable(name: "ProgrammingOverride");
migrationBuilder.DropTable(name: "Shows");
migrationBuilder.DropTable(name: "Channels");
}
}
}
@@ -1,61 +1,61 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddBumpers : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "BumpersEnabled",
table: "Channels",
type: "boolean",
nullable: false,
defaultValue: false
);
migrationBuilder.CreateTable(
name: "BumperAssets",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
FromShowId = table.Column<Guid>(type: "uuid", nullable: false),
ToShowId = table.Column<Guid>(type: "uuid", nullable: false),
Signature = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_BumperAssets", x => x.Id);
}
);
migrationBuilder.CreateIndex(
name: "IX_BumperAssets_FromShowId_ToShowId_Signature",
table: "BumperAssets",
columns: new[] { "FromShowId", "ToShowId", "Signature" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "BumperAssets");
migrationBuilder.DropColumn(name: "BumpersEnabled", table: "Channels");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddBumpers : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "BumpersEnabled",
table: "Channels",
type: "boolean",
nullable: false,
defaultValue: false
);
migrationBuilder.CreateTable(
name: "BumperAssets",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
FromShowId = table.Column<Guid>(type: "uuid", nullable: false),
ToShowId = table.Column<Guid>(type: "uuid", nullable: false),
Signature = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_BumperAssets", x => x.Id);
}
);
migrationBuilder.CreateIndex(
name: "IX_BumperAssets_FromShowId_ToShowId_Signature",
table: "BumperAssets",
columns: new[] { "FromShowId", "ToShowId", "Signature" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "BumperAssets");
migrationBuilder.DropColumn(name: "BumpersEnabled", table: "Channels");
}
}
}
@@ -1,118 +1,118 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ChannelBumperSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "BumperAccentColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "0x38bdf8"
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "0x0b1020"
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundColor2",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "0x1e293b"
);
migrationBuilder.AddColumn<int>(
name: "BumperDurationSeconds",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 8
);
migrationBuilder.AddColumn<int>(
name: "BumperFont",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "BumperMinIntervalMinutes",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<string>(
name: "BumperNextLabel",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "ДАЛЕЕ"
);
migrationBuilder.AddColumn<string>(
name: "BumperNowLabel",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "СЕЙЧАС"
);
migrationBuilder.AddColumn<bool>(
name: "BumperOnlyBetweenDifferentShows",
table: "Channels",
type: "boolean",
nullable: false,
defaultValue: true
);
migrationBuilder.AddColumn<string>(
name: "BumperTextColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "white"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "BumperAccentColor", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundColor", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundColor2", table: "Channels");
migrationBuilder.DropColumn(name: "BumperDurationSeconds", table: "Channels");
migrationBuilder.DropColumn(name: "BumperFont", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMinIntervalMinutes", table: "Channels");
migrationBuilder.DropColumn(name: "BumperNextLabel", table: "Channels");
migrationBuilder.DropColumn(name: "BumperNowLabel", table: "Channels");
migrationBuilder.DropColumn(name: "BumperOnlyBetweenDifferentShows", table: "Channels");
migrationBuilder.DropColumn(name: "BumperTextColor", table: "Channels");
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ChannelBumperSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "BumperAccentColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "0x38bdf8"
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "0x0b1020"
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundColor2",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "0x1e293b"
);
migrationBuilder.AddColumn<int>(
name: "BumperDurationSeconds",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 8
);
migrationBuilder.AddColumn<int>(
name: "BumperFont",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "BumperMinIntervalMinutes",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<string>(
name: "BumperNextLabel",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "ДАЛЕЕ"
);
migrationBuilder.AddColumn<string>(
name: "BumperNowLabel",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "СЕЙЧАС"
);
migrationBuilder.AddColumn<bool>(
name: "BumperOnlyBetweenDifferentShows",
table: "Channels",
type: "boolean",
nullable: false,
defaultValue: true
);
migrationBuilder.AddColumn<string>(
name: "BumperTextColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: "white"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "BumperAccentColor", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundColor", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundColor2", table: "Channels");
migrationBuilder.DropColumn(name: "BumperDurationSeconds", table: "Channels");
migrationBuilder.DropColumn(name: "BumperFont", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMinIntervalMinutes", table: "Channels");
migrationBuilder.DropColumn(name: "BumperNextLabel", table: "Channels");
migrationBuilder.DropColumn(name: "BumperNowLabel", table: "Channels");
migrationBuilder.DropColumn(name: "BumperOnlyBetweenDifferentShows", table: "Channels");
migrationBuilder.DropColumn(name: "BumperTextColor", table: "Channels");
}
}
}
@@ -1,97 +1,97 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperFilesAndJingles : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundExtension",
table: "Channels",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "BumperMode",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<string>(
name: "BumperMusicExtension",
table: "Channels",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "BumperRevision",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "NextJingleIndex",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.CreateTable(
name: "ChannelJingle",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelJingle", x => x.Id);
table.ForeignKey(
name: "FK_ChannelJingle_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelJingle_ChannelId_Position",
table: "ChannelJingle",
columns: new[] { "ChannelId", "Position" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelJingle");
migrationBuilder.DropColumn(name: "BumperBackgroundExtension", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMode", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMusicExtension", table: "Channels");
migrationBuilder.DropColumn(name: "BumperRevision", table: "Channels");
migrationBuilder.DropColumn(name: "NextJingleIndex", table: "Channels");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperFilesAndJingles : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundExtension",
table: "Channels",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "BumperMode",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<string>(
name: "BumperMusicExtension",
table: "Channels",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "BumperRevision",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "NextJingleIndex",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.CreateTable(
name: "ChannelJingle",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelJingle", x => x.Id);
table.ForeignKey(
name: "FK_ChannelJingle_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelJingle_ChannelId_Position",
table: "ChannelJingle",
columns: new[] { "ChannelId", "Position" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelJingle");
migrationBuilder.DropColumn(name: "BumperBackgroundExtension", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMode", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMusicExtension", table: "Channels");
migrationBuilder.DropColumn(name: "BumperRevision", table: "Channels");
migrationBuilder.DropColumn(name: "NextJingleIndex", table: "Channels");
}
}
}
@@ -1,41 +1,41 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AppSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppSettings",
columns: table => new
{
Key = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
Value = table.Column<string>(
type: "character varying(1024)",
maxLength: 1024,
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_AppSettings", x => x.Key);
}
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "AppSettings");
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AppSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppSettings",
columns: table => new
{
Key = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
Value = table.Column<string>(
type: "character varying(1024)",
maxLength: 1024,
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_AppSettings", x => x.Key);
}
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "AppSettings");
}
}
}
@@ -1,57 +1,57 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowMetadata : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "MetadataExternalId",
table: "Shows",
type: "character varying(64)",
maxLength: 64,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "MetadataProvider",
table: "Shows",
type: "character varying(16)",
maxLength: 16,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "PosterPath",
table: "Shows",
type: "character varying(256)",
maxLength: 256,
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "Year",
table: "Shows",
type: "integer",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "MetadataExternalId", table: "Shows");
migrationBuilder.DropColumn(name: "MetadataProvider", table: "Shows");
migrationBuilder.DropColumn(name: "PosterPath", table: "Shows");
migrationBuilder.DropColumn(name: "Year", table: "Shows");
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowMetadata : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "MetadataExternalId",
table: "Shows",
type: "character varying(64)",
maxLength: 64,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "MetadataProvider",
table: "Shows",
type: "character varying(16)",
maxLength: 16,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "PosterPath",
table: "Shows",
type: "character varying(256)",
maxLength: 256,
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "Year",
table: "Shows",
type: "integer",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "MetadataExternalId", table: "Shows");
migrationBuilder.DropColumn(name: "MetadataProvider", table: "Shows");
migrationBuilder.DropColumn(name: "PosterPath", table: "Shows");
migrationBuilder.DropColumn(name: "Year", table: "Shows");
}
}
}
@@ -1,76 +1,76 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class EpisodeMetadata : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateOnly>(
name: "AirDate",
table: "ShowEpisode",
type: "date",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "Episode",
table: "ShowEpisode",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "Overview",
table: "ShowEpisode",
type: "character varying(4096)",
maxLength: 4096,
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "Season",
table: "ShowEpisode",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "StillPath",
table: "ShowEpisode",
type: "character varying(256)",
maxLength: 256,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "Title",
table: "ShowEpisode",
type: "character varying(512)",
maxLength: 512,
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "AirDate", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "Episode", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "Overview", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "Season", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "StillPath", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "Title", table: "ShowEpisode");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class EpisodeMetadata : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateOnly>(
name: "AirDate",
table: "ShowEpisode",
type: "date",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "Episode",
table: "ShowEpisode",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "Overview",
table: "ShowEpisode",
type: "character varying(4096)",
maxLength: 4096,
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "Season",
table: "ShowEpisode",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "StillPath",
table: "ShowEpisode",
type: "character varying(256)",
maxLength: 256,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "Title",
table: "ShowEpisode",
type: "character varying(512)",
maxLength: 512,
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "AirDate", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "Episode", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "Overview", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "Season", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "StillPath", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "Title", table: "ShowEpisode");
}
}
}
@@ -1,246 +1,246 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperTemplates : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelJingle");
migrationBuilder.DropColumn(name: "BumperAccentColor", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundColor", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundColor2", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundExtension", table: "Channels");
migrationBuilder.DropColumn(name: "BumperDurationSeconds", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMode", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMusicExtension", table: "Channels");
migrationBuilder.DropColumn(name: "BumperTextColor", table: "Channels");
migrationBuilder.RenameColumn(
name: "NextJingleIndex",
table: "Channels",
newName: "NextBumperIndex"
);
// Ревизия файлов уехала на блоки заставок — старый счётчик не переносим, стратегия по
// умолчанию Rotation (0).
migrationBuilder.DropColumn(name: "BumperRevision", table: "Channels");
migrationBuilder.AddColumn<int>(
name: "BumperSelection",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.CreateTable(
name: "BumperTemplate",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
Name = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
BackgroundColor = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: false
),
BackgroundColor2 = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: false
),
AccentColor = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: false
),
TextColor = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: false
),
BackgroundImageExtension = table.Column<string>(
type: "character varying(16)",
maxLength: 16,
nullable: true
),
AudioExtension = table.Column<string>(
type: "character varying(16)",
maxLength: 16,
nullable: true
),
AudioDurationSeconds = table.Column<double>(
type: "double precision",
nullable: true
),
Revision = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_BumperTemplate", x => x.Id);
table.ForeignKey(
name: "FK_BumperTemplate_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_BumperTemplate_ChannelId_Position",
table: "BumperTemplate",
columns: new[] { "ChannelId", "Position" }
);
// Каждому существующему каналу — дефолтный блок заставки (Position 0, без звука/фона).
migrationBuilder.Sql(
"""
INSERT INTO "BumperTemplate"
("Id", "ChannelId", "Position", "Name", "BackgroundColor", "BackgroundColor2",
"AccentColor", "TextColor", "Revision", "CreatedAt")
SELECT gen_random_uuid(), c."Id", 0, 'Заставка 1', '0x0b1020', '0x1e293b',
'0x38bdf8', 'white', 0, now()
FROM "Channels" c;
"""
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "BumperTemplate");
migrationBuilder.RenameColumn(
name: "NextBumperIndex",
table: "Channels",
newName: "NextJingleIndex"
);
migrationBuilder.DropColumn(name: "BumperSelection", table: "Channels");
migrationBuilder.AddColumn<int>(
name: "BumperRevision",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<string>(
name: "BumperAccentColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundColor2",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundExtension",
table: "Channels",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "BumperDurationSeconds",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "BumperMode",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<string>(
name: "BumperMusicExtension",
table: "Channels",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "BumperTextColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.CreateTable(
name: "ChannelJingle",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelJingle", x => x.Id);
table.ForeignKey(
name: "FK_ChannelJingle_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelJingle_ChannelId_Position",
table: "ChannelJingle",
columns: new[] { "ChannelId", "Position" }
);
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperTemplates : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelJingle");
migrationBuilder.DropColumn(name: "BumperAccentColor", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundColor", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundColor2", table: "Channels");
migrationBuilder.DropColumn(name: "BumperBackgroundExtension", table: "Channels");
migrationBuilder.DropColumn(name: "BumperDurationSeconds", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMode", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMusicExtension", table: "Channels");
migrationBuilder.DropColumn(name: "BumperTextColor", table: "Channels");
migrationBuilder.RenameColumn(
name: "NextJingleIndex",
table: "Channels",
newName: "NextBumperIndex"
);
// Ревизия файлов уехала на блоки заставок — старый счётчик не переносим, стратегия по
// умолчанию Rotation (0).
migrationBuilder.DropColumn(name: "BumperRevision", table: "Channels");
migrationBuilder.AddColumn<int>(
name: "BumperSelection",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.CreateTable(
name: "BumperTemplate",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
Name = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
BackgroundColor = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: false
),
BackgroundColor2 = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: false
),
AccentColor = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: false
),
TextColor = table.Column<string>(
type: "character varying(32)",
maxLength: 32,
nullable: false
),
BackgroundImageExtension = table.Column<string>(
type: "character varying(16)",
maxLength: 16,
nullable: true
),
AudioExtension = table.Column<string>(
type: "character varying(16)",
maxLength: 16,
nullable: true
),
AudioDurationSeconds = table.Column<double>(
type: "double precision",
nullable: true
),
Revision = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_BumperTemplate", x => x.Id);
table.ForeignKey(
name: "FK_BumperTemplate_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_BumperTemplate_ChannelId_Position",
table: "BumperTemplate",
columns: new[] { "ChannelId", "Position" }
);
// Каждому существующему каналу — дефолтный блок заставки (Position 0, без звука/фона).
migrationBuilder.Sql(
"""
INSERT INTO "BumperTemplate"
("Id", "ChannelId", "Position", "Name", "BackgroundColor", "BackgroundColor2",
"AccentColor", "TextColor", "Revision", "CreatedAt")
SELECT gen_random_uuid(), c."Id", 0, 'Заставка 1', '0x0b1020', '0x1e293b',
'0x38bdf8', 'white', 0, now()
FROM "Channels" c;
"""
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "BumperTemplate");
migrationBuilder.RenameColumn(
name: "NextBumperIndex",
table: "Channels",
newName: "NextJingleIndex"
);
migrationBuilder.DropColumn(name: "BumperSelection", table: "Channels");
migrationBuilder.AddColumn<int>(
name: "BumperRevision",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<string>(
name: "BumperAccentColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundColor2",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<string>(
name: "BumperBackgroundExtension",
table: "Channels",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "BumperDurationSeconds",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "BumperMode",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<string>(
name: "BumperMusicExtension",
table: "Channels",
type: "text",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "BumperTextColor",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.CreateTable(
name: "ChannelJingle",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelJingle", x => x.Id);
table.ForeignKey(
name: "FK_ChannelJingle_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelJingle_ChannelId_Position",
table: "ChannelJingle",
columns: new[] { "ChannelId", "Position" }
);
}
}
}
@@ -1,27 +1,27 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowOriginalName : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "OriginalName",
table: "Shows",
type: "text",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "OriginalName", table: "Shows");
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowOriginalName : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "OriginalName",
table: "Shows",
type: "text",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "OriginalName", table: "Shows");
}
}
}
@@ -1,54 +1,54 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ImageRegistry : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Images",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Category = table.Column<int>(type: "integer", nullable: false),
FileExtension = table.Column<string>(
type: "character varying(16)",
maxLength: 16,
nullable: false
),
OriginalFileName = table.Column<string>(
type: "character varying(512)",
maxLength: 512,
nullable: true
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Images", x => x.Id);
}
);
migrationBuilder.CreateIndex(
name: "IX_Images_Category_CreatedAt",
table: "Images",
columns: new[] { "Category", "CreatedAt" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "Images");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ImageRegistry : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Images",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Category = table.Column<int>(type: "integer", nullable: false),
FileExtension = table.Column<string>(
type: "character varying(16)",
maxLength: 16,
nullable: false
),
OriginalFileName = table.Column<string>(
type: "character varying(512)",
maxLength: 512,
nullable: true
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Images", x => x.Id);
}
);
migrationBuilder.CreateIndex(
name: "IX_Images_Category_CreatedAt",
table: "Images",
columns: new[] { "Category", "CreatedAt" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "Images");
}
}
}
@@ -1,78 +1,78 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowPosterImage : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "OriginalName",
table: "Shows",
type: "character varying(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "text",
oldNullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "PosterImageId",
table: "Shows",
type: "uuid",
nullable: true
);
// Переносим существующие постеры шоу в общий реестр изображений: на каждый постер —
// запись Images (Category=1 ShowPoster) с расширением из старого пути; файлы перекладывает
// startup-шаг RelocateLegacyImagesAsync. Затем удаляем колонку PosterPath.
migrationBuilder.Sql(
"""
DO $$
DECLARE r RECORD; img uuid;
BEGIN
FOR r IN SELECT "Id", "PosterPath" FROM "Shows" WHERE "PosterPath" IS NOT NULL LOOP
img := gen_random_uuid();
INSERT INTO "Images" ("Id", "Category", "FileExtension", "OriginalFileName", "CreatedAt")
VALUES (img, 1, lower(coalesce(substring(r."PosterPath" from '\.[^.]*$'), '.jpg')), 'poster', now());
UPDATE "Shows" SET "PosterImageId" = img WHERE "Id" = r."Id";
END LOOP;
END $$;
"""
);
migrationBuilder.DropColumn(name: "PosterPath", table: "Shows");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "PosterImageId", table: "Shows");
migrationBuilder.AlterColumn<string>(
name: "OriginalName",
table: "Shows",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256,
oldNullable: true
);
migrationBuilder.AddColumn<string>(
name: "PosterPath",
table: "Shows",
type: "character varying(256)",
maxLength: 256,
nullable: true
);
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowPosterImage : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "OriginalName",
table: "Shows",
type: "character varying(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "text",
oldNullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "PosterImageId",
table: "Shows",
type: "uuid",
nullable: true
);
// Переносим существующие постеры шоу в общий реестр изображений: на каждый постер —
// запись Images (Category=1 ShowPoster) с расширением из старого пути; файлы перекладывает
// startup-шаг RelocateLegacyImagesAsync. Затем удаляем колонку PosterPath.
migrationBuilder.Sql(
"""
DO $$
DECLARE r RECORD; img uuid;
BEGIN
FOR r IN SELECT "Id", "PosterPath" FROM "Shows" WHERE "PosterPath" IS NOT NULL LOOP
img := gen_random_uuid();
INSERT INTO "Images" ("Id", "Category", "FileExtension", "OriginalFileName", "CreatedAt")
VALUES (img, 1, lower(coalesce(substring(r."PosterPath" from '\.[^.]*$'), '.jpg')), 'poster', now());
UPDATE "Shows" SET "PosterImageId" = img WHERE "Id" = r."Id";
END LOOP;
END $$;
"""
);
migrationBuilder.DropColumn(name: "PosterPath", table: "Shows");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "PosterImageId", table: "Shows");
migrationBuilder.AlterColumn<string>(
name: "OriginalName",
table: "Shows",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256,
oldNullable: true
);
migrationBuilder.AddColumn<string>(
name: "PosterPath",
table: "Shows",
type: "character varying(256)",
maxLength: 256,
nullable: true
);
}
}
}
@@ -1,89 +1,89 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class EpisodeStillAndBumperBgImages : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "StillImageId",
table: "ShowEpisode",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "BackgroundImageId",
table: "BumperTemplate",
type: "uuid",
nullable: true
);
// Кадры серий → реестр (Category=2 EpisodeStill); файлы перекладывает RelocateLegacyImagesAsync.
migrationBuilder.Sql(
"""
DO $$
DECLARE r RECORD; img uuid;
BEGIN
FOR r IN SELECT "Id", "StillPath" FROM "ShowEpisode" WHERE "StillPath" IS NOT NULL LOOP
img := gen_random_uuid();
INSERT INTO "Images" ("Id", "Category", "FileExtension", "OriginalFileName", "CreatedAt")
VALUES (img, 2, lower(coalesce(substring(r."StillPath" from '\.[^.]*$'), '.jpg')), 'still', now());
UPDATE "ShowEpisode" SET "StillImageId" = img WHERE "Id" = r."Id";
END LOOP;
END $$;
"""
);
// Фоны блоков заставок → реестр (Category=3 BumperBackground).
migrationBuilder.Sql(
"""
DO $$
DECLARE r RECORD; img uuid;
BEGIN
FOR r IN SELECT "Id", "BackgroundImageExtension" FROM "BumperTemplate" WHERE "BackgroundImageExtension" IS NOT NULL LOOP
img := gen_random_uuid();
INSERT INTO "Images" ("Id", "Category", "FileExtension", "OriginalFileName", "CreatedAt")
VALUES (img, 3, lower(r."BackgroundImageExtension"), 'background', now());
UPDATE "BumperTemplate" SET "BackgroundImageId" = img WHERE "Id" = r."Id";
END LOOP;
END $$;
"""
);
migrationBuilder.DropColumn(name: "StillPath", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "BackgroundImageExtension", table: "BumperTemplate");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "StillImageId", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "BackgroundImageId", table: "BumperTemplate");
migrationBuilder.AddColumn<string>(
name: "StillPath",
table: "ShowEpisode",
type: "character varying(256)",
maxLength: 256,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "BackgroundImageExtension",
table: "BumperTemplate",
type: "character varying(16)",
maxLength: 16,
nullable: true
);
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class EpisodeStillAndBumperBgImages : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "StillImageId",
table: "ShowEpisode",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "BackgroundImageId",
table: "BumperTemplate",
type: "uuid",
nullable: true
);
// Кадры серий → реестр (Category=2 EpisodeStill); файлы перекладывает RelocateLegacyImagesAsync.
migrationBuilder.Sql(
"""
DO $$
DECLARE r RECORD; img uuid;
BEGIN
FOR r IN SELECT "Id", "StillPath" FROM "ShowEpisode" WHERE "StillPath" IS NOT NULL LOOP
img := gen_random_uuid();
INSERT INTO "Images" ("Id", "Category", "FileExtension", "OriginalFileName", "CreatedAt")
VALUES (img, 2, lower(coalesce(substring(r."StillPath" from '\.[^.]*$'), '.jpg')), 'still', now());
UPDATE "ShowEpisode" SET "StillImageId" = img WHERE "Id" = r."Id";
END LOOP;
END $$;
"""
);
// Фоны блоков заставок → реестр (Category=3 BumperBackground).
migrationBuilder.Sql(
"""
DO $$
DECLARE r RECORD; img uuid;
BEGIN
FOR r IN SELECT "Id", "BackgroundImageExtension" FROM "BumperTemplate" WHERE "BackgroundImageExtension" IS NOT NULL LOOP
img := gen_random_uuid();
INSERT INTO "Images" ("Id", "Category", "FileExtension", "OriginalFileName", "CreatedAt")
VALUES (img, 3, lower(r."BackgroundImageExtension"), 'background', now());
UPDATE "BumperTemplate" SET "BackgroundImageId" = img WHERE "Id" = r."Id";
END LOOP;
END $$;
"""
);
migrationBuilder.DropColumn(name: "StillPath", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "BackgroundImageExtension", table: "BumperTemplate");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "StillImageId", table: "ShowEpisode");
migrationBuilder.DropColumn(name: "BackgroundImageId", table: "BumperTemplate");
migrationBuilder.AddColumn<string>(
name: "StillPath",
table: "ShowEpisode",
type: "character varying(256)",
maxLength: 256,
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "BackgroundImageExtension",
table: "BumperTemplate",
type: "character varying(16)",
maxLength: 16,
nullable: true
);
}
}
}
@@ -1,131 +1,131 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperTextVariants : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "BumperTextVariant",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
BumperTemplateId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
Name = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
Kind = table.Column<int>(type: "integer", nullable: false),
NowLabel = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
NextLabel = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
Line1 = table.Column<string>(
type: "character varying(120)",
maxLength: 120,
nullable: false
),
Line2 = table.Column<string>(
type: "character varying(120)",
maxLength: 120,
nullable: false
),
Trigger = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_BumperTextVariant", x => x.Id);
table.ForeignKey(
name: "FK_BumperTextVariant_BumperTemplate_BumperTemplateId",
column: x => x.BumperTemplateId,
principalTable: "BumperTemplate",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_BumperTextVariant_BumperTemplateId_Position",
table: "BumperTextVariant",
columns: new[] { "BumperTemplateId", "Position" }
);
// Каждому блоку — дефолтный подблок «Сейчас/Далее» с прежними подписями канала; правило
// показа переносим из старой галочки (только на смене шоу → OnShowChange=0, иначе Both=2).
migrationBuilder.Sql(
"""
DO $$
DECLARE r RECORD;
BEGIN
FOR r IN
SELECT t."Id" AS tid, c."BumperNowLabel" AS nl, c."BumperNextLabel" AS xl,
c."BumperOnlyBetweenDifferentShows" AS only_diff
FROM "BumperTemplate" t
JOIN "Channels" c ON c."Id" = t."ChannelId"
LOOP
INSERT INTO "BumperTextVariant"
("Id", "BumperTemplateId", "Position", "Name", "Kind",
"NowLabel", "NextLabel", "Line1", "Line2", "Trigger", "CreatedAt")
VALUES (gen_random_uuid(), r.tid, 0, 'Текст 1', 0,
COALESCE(NULLIF(r.nl, ''), 'СЕЙЧАС'), COALESCE(NULLIF(r.xl, ''), 'ДАЛЕЕ'),
'', '', CASE WHEN r.only_diff THEN 0 ELSE 2 END, now());
END LOOP;
END $$;
"""
);
migrationBuilder.DropColumn(name: "BumperNextLabel", table: "Channels");
migrationBuilder.DropColumn(name: "BumperNowLabel", table: "Channels");
migrationBuilder.DropColumn(name: "BumperOnlyBetweenDifferentShows", table: "Channels");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "BumperTextVariant");
migrationBuilder.AddColumn<string>(
name: "BumperNextLabel",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<string>(
name: "BumperNowLabel",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<bool>(
name: "BumperOnlyBetweenDifferentShows",
table: "Channels",
type: "boolean",
nullable: false,
defaultValue: false
);
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperTextVariants : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "BumperTextVariant",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
BumperTemplateId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
Name = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
Kind = table.Column<int>(type: "integer", nullable: false),
NowLabel = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
NextLabel = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
Line1 = table.Column<string>(
type: "character varying(120)",
maxLength: 120,
nullable: false
),
Line2 = table.Column<string>(
type: "character varying(120)",
maxLength: 120,
nullable: false
),
Trigger = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_BumperTextVariant", x => x.Id);
table.ForeignKey(
name: "FK_BumperTextVariant_BumperTemplate_BumperTemplateId",
column: x => x.BumperTemplateId,
principalTable: "BumperTemplate",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_BumperTextVariant_BumperTemplateId_Position",
table: "BumperTextVariant",
columns: new[] { "BumperTemplateId", "Position" }
);
// Каждому блоку — дефолтный подблок «Сейчас/Далее» с прежними подписями канала; правило
// показа переносим из старой галочки (только на смене шоу → OnShowChange=0, иначе Both=2).
migrationBuilder.Sql(
"""
DO $$
DECLARE r RECORD;
BEGIN
FOR r IN
SELECT t."Id" AS tid, c."BumperNowLabel" AS nl, c."BumperNextLabel" AS xl,
c."BumperOnlyBetweenDifferentShows" AS only_diff
FROM "BumperTemplate" t
JOIN "Channels" c ON c."Id" = t."ChannelId"
LOOP
INSERT INTO "BumperTextVariant"
("Id", "BumperTemplateId", "Position", "Name", "Kind",
"NowLabel", "NextLabel", "Line1", "Line2", "Trigger", "CreatedAt")
VALUES (gen_random_uuid(), r.tid, 0, 'Текст 1', 0,
COALESCE(NULLIF(r.nl, ''), 'СЕЙЧАС'), COALESCE(NULLIF(r.xl, ''), 'ДАЛЕЕ'),
'', '', CASE WHEN r.only_diff THEN 0 ELSE 2 END, now());
END LOOP;
END $$;
"""
);
migrationBuilder.DropColumn(name: "BumperNextLabel", table: "Channels");
migrationBuilder.DropColumn(name: "BumperNowLabel", table: "Channels");
migrationBuilder.DropColumn(name: "BumperOnlyBetweenDifferentShows", table: "Channels");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "BumperTextVariant");
migrationBuilder.AddColumn<string>(
name: "BumperNextLabel",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<string>(
name: "BumperNowLabel",
table: "Channels",
type: "text",
nullable: false,
defaultValue: ""
);
migrationBuilder.AddColumn<bool>(
name: "BumperOnlyBetweenDifferentShows",
table: "Channels",
type: "boolean",
nullable: false,
defaultValue: false
);
}
}
}
@@ -1,125 +1,125 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperChancesWeightsAndScheduleVariant : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_BumperTextVariant_BumperTemplate_BumperTemplateId",
table: "BumperTextVariant"
);
migrationBuilder.DropPrimaryKey(
name: "PK_BumperTextVariant",
table: "BumperTextVariant"
);
migrationBuilder.RenameTable(name: "BumperTextVariant", newName: "BumperTextVariants");
migrationBuilder.RenameIndex(
name: "IX_BumperTextVariant_BumperTemplateId_Position",
table: "BumperTextVariants",
newName: "IX_BumperTextVariants_BumperTemplateId_Position"
);
migrationBuilder.AddColumn<Guid>(
name: "BumperVariantId",
table: "ScheduleEntries",
type: "uuid",
nullable: true
);
// Существующим каналам — 1.0 (заставка на каждом подходящем переходе, как было до фичи).
migrationBuilder.AddColumn<double>(
name: "BumperEpisodeChangeChance",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 1.0
);
migrationBuilder.AddColumn<double>(
name: "BumperShowChangeChance",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 1.0
);
migrationBuilder.AddColumn<int>(
name: "Weight",
table: "BumperTextVariants",
type: "integer",
nullable: false,
defaultValue: 1
);
migrationBuilder.AddPrimaryKey(
name: "PK_BumperTextVariants",
table: "BumperTextVariants",
column: "Id"
);
migrationBuilder.AddForeignKey(
name: "FK_BumperTextVariants_BumperTemplate_BumperTemplateId",
table: "BumperTextVariants",
column: "BumperTemplateId",
principalTable: "BumperTemplate",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_BumperTextVariants_BumperTemplate_BumperTemplateId",
table: "BumperTextVariants"
);
migrationBuilder.DropPrimaryKey(
name: "PK_BumperTextVariants",
table: "BumperTextVariants"
);
migrationBuilder.DropColumn(name: "BumperVariantId", table: "ScheduleEntries");
migrationBuilder.DropColumn(name: "BumperEpisodeChangeChance", table: "Channels");
migrationBuilder.DropColumn(name: "BumperShowChangeChance", table: "Channels");
migrationBuilder.DropColumn(name: "Weight", table: "BumperTextVariants");
migrationBuilder.RenameTable(name: "BumperTextVariants", newName: "BumperTextVariant");
migrationBuilder.RenameIndex(
name: "IX_BumperTextVariants_BumperTemplateId_Position",
table: "BumperTextVariant",
newName: "IX_BumperTextVariant_BumperTemplateId_Position"
);
migrationBuilder.AddPrimaryKey(
name: "PK_BumperTextVariant",
table: "BumperTextVariant",
column: "Id"
);
migrationBuilder.AddForeignKey(
name: "FK_BumperTextVariant_BumperTemplate_BumperTemplateId",
table: "BumperTextVariant",
column: "BumperTemplateId",
principalTable: "BumperTemplate",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperChancesWeightsAndScheduleVariant : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_BumperTextVariant_BumperTemplate_BumperTemplateId",
table: "BumperTextVariant"
);
migrationBuilder.DropPrimaryKey(
name: "PK_BumperTextVariant",
table: "BumperTextVariant"
);
migrationBuilder.RenameTable(name: "BumperTextVariant", newName: "BumperTextVariants");
migrationBuilder.RenameIndex(
name: "IX_BumperTextVariant_BumperTemplateId_Position",
table: "BumperTextVariants",
newName: "IX_BumperTextVariants_BumperTemplateId_Position"
);
migrationBuilder.AddColumn<Guid>(
name: "BumperVariantId",
table: "ScheduleEntries",
type: "uuid",
nullable: true
);
// Существующим каналам — 1.0 (заставка на каждом подходящем переходе, как было до фичи).
migrationBuilder.AddColumn<double>(
name: "BumperEpisodeChangeChance",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 1.0
);
migrationBuilder.AddColumn<double>(
name: "BumperShowChangeChance",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 1.0
);
migrationBuilder.AddColumn<int>(
name: "Weight",
table: "BumperTextVariants",
type: "integer",
nullable: false,
defaultValue: 1
);
migrationBuilder.AddPrimaryKey(
name: "PK_BumperTextVariants",
table: "BumperTextVariants",
column: "Id"
);
migrationBuilder.AddForeignKey(
name: "FK_BumperTextVariants_BumperTemplate_BumperTemplateId",
table: "BumperTextVariants",
column: "BumperTemplateId",
principalTable: "BumperTemplate",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_BumperTextVariants_BumperTemplate_BumperTemplateId",
table: "BumperTextVariants"
);
migrationBuilder.DropPrimaryKey(
name: "PK_BumperTextVariants",
table: "BumperTextVariants"
);
migrationBuilder.DropColumn(name: "BumperVariantId", table: "ScheduleEntries");
migrationBuilder.DropColumn(name: "BumperEpisodeChangeChance", table: "Channels");
migrationBuilder.DropColumn(name: "BumperShowChangeChance", table: "Channels");
migrationBuilder.DropColumn(name: "Weight", table: "BumperTextVariants");
migrationBuilder.RenameTable(name: "BumperTextVariants", newName: "BumperTextVariant");
migrationBuilder.RenameIndex(
name: "IX_BumperTextVariants_BumperTemplateId_Position",
table: "BumperTextVariant",
newName: "IX_BumperTextVariant_BumperTemplateId_Position"
);
migrationBuilder.AddPrimaryKey(
name: "PK_BumperTextVariant",
table: "BumperTextVariant",
column: "Id"
);
migrationBuilder.AddForeignKey(
name: "FK_BumperTextVariant_BumperTemplate_BumperTemplateId",
table: "BumperTextVariant",
column: "BumperTemplateId",
principalTable: "BumperTemplate",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
}
}
@@ -1,59 +1,59 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ChannelShowPreferredHours : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "PreferredWeightMultiplier",
table: "ChannelShow",
type: "integer",
nullable: false,
defaultValue: 3
);
migrationBuilder.CreateTable(
name: "ChannelShowHour",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelShowId = table.Column<Guid>(type: "uuid", nullable: false),
StartHour = table.Column<int>(type: "integer", nullable: false),
EndHour = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelShowHour", x => x.Id);
table.ForeignKey(
name: "FK_ChannelShowHour_ChannelShow_ChannelShowId",
column: x => x.ChannelShowId,
principalTable: "ChannelShow",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelShowHour_ChannelShowId",
table: "ChannelShowHour",
column: "ChannelShowId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelShowHour");
migrationBuilder.DropColumn(name: "PreferredWeightMultiplier", table: "ChannelShow");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ChannelShowPreferredHours : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "PreferredWeightMultiplier",
table: "ChannelShow",
type: "integer",
nullable: false,
defaultValue: 3
);
migrationBuilder.CreateTable(
name: "ChannelShowHour",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelShowId = table.Column<Guid>(type: "uuid", nullable: false),
StartHour = table.Column<int>(type: "integer", nullable: false),
EndHour = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelShowHour", x => x.Id);
table.ForeignKey(
name: "FK_ChannelShowHour_ChannelShow_ChannelShowId",
column: x => x.ChannelShowId,
principalTable: "ChannelShow",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelShowHour_ChannelShowId",
table: "ChannelShowHour",
column: "ChannelShowId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelShowHour");
migrationBuilder.DropColumn(name: "PreferredWeightMultiplier", table: "ChannelShow");
}
}
}
@@ -1,102 +1,102 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class WeeklyProgrammingOverrides : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "StartsAtUtc",
table: "ProgrammingOverride",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone"
);
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "EndsAtUtc",
table: "ProgrammingOverride",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone"
);
migrationBuilder.AddColumn<int>(
name: "DayOfWeek",
table: "ProgrammingOverride",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "EndMinute",
table: "ProgrammingOverride",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "Recurrence",
table: "ProgrammingOverride",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "StartMinute",
table: "ProgrammingOverride",
type: "integer",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "DayOfWeek", table: "ProgrammingOverride");
migrationBuilder.DropColumn(name: "EndMinute", table: "ProgrammingOverride");
migrationBuilder.DropColumn(name: "Recurrence", table: "ProgrammingOverride");
migrationBuilder.DropColumn(name: "StartMinute", table: "ProgrammingOverride");
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "StartsAtUtc",
table: "ProgrammingOverride",
type: "timestamp with time zone",
nullable: false,
defaultValue: new DateTimeOffset(
new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
new TimeSpan(0, 0, 0, 0, 0)
),
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone",
oldNullable: true
);
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "EndsAtUtc",
table: "ProgrammingOverride",
type: "timestamp with time zone",
nullable: false,
defaultValue: new DateTimeOffset(
new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
new TimeSpan(0, 0, 0, 0, 0)
),
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone",
oldNullable: true
);
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class WeeklyProgrammingOverrides : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "StartsAtUtc",
table: "ProgrammingOverride",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone"
);
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "EndsAtUtc",
table: "ProgrammingOverride",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone"
);
migrationBuilder.AddColumn<int>(
name: "DayOfWeek",
table: "ProgrammingOverride",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "EndMinute",
table: "ProgrammingOverride",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "Recurrence",
table: "ProgrammingOverride",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "StartMinute",
table: "ProgrammingOverride",
type: "integer",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "DayOfWeek", table: "ProgrammingOverride");
migrationBuilder.DropColumn(name: "EndMinute", table: "ProgrammingOverride");
migrationBuilder.DropColumn(name: "Recurrence", table: "ProgrammingOverride");
migrationBuilder.DropColumn(name: "StartMinute", table: "ProgrammingOverride");
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "StartsAtUtc",
table: "ProgrammingOverride",
type: "timestamp with time zone",
nullable: false,
defaultValue: new DateTimeOffset(
new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
new TimeSpan(0, 0, 0, 0, 0)
),
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone",
oldNullable: true
);
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "EndsAtUtc",
table: "ProgrammingOverride",
type: "timestamp with time zone",
nullable: false,
defaultValue: new DateTimeOffset(
new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
new TimeSpan(0, 0, 0, 0, 0)
),
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone",
oldNullable: true
);
}
}
}
@@ -1,49 +1,49 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperAssetRenderContext : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "ChannelId",
table: "BumperAssets",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000")
);
migrationBuilder.AddColumn<Guid>(
name: "TemplateId",
table: "BumperAssets",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000")
);
migrationBuilder.AddColumn<Guid>(
name: "VariantId",
table: "BumperAssets",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000")
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "ChannelId", table: "BumperAssets");
migrationBuilder.DropColumn(name: "TemplateId", table: "BumperAssets");
migrationBuilder.DropColumn(name: "VariantId", table: "BumperAssets");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class BumperAssetRenderContext : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "ChannelId",
table: "BumperAssets",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000")
);
migrationBuilder.AddColumn<Guid>(
name: "TemplateId",
table: "BumperAssets",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000")
);
migrationBuilder.AddColumn<Guid>(
name: "VariantId",
table: "BumperAssets",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000")
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "ChannelId", table: "BumperAssets");
migrationBuilder.DropColumn(name: "TemplateId", table: "BumperAssets");
migrationBuilder.DropColumn(name: "VariantId", table: "BumperAssets");
}
}
}
@@ -1,37 +1,37 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class MediaProcessingTiming : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<TimeSpan>(
name: "ProcessingDuration",
table: "MediaAssets",
type: "interval",
nullable: true
);
migrationBuilder.AddColumn<DateTimeOffset>(
name: "ProcessingStartedAt",
table: "MediaAssets",
type: "timestamp with time zone",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "ProcessingDuration", table: "MediaAssets");
migrationBuilder.DropColumn(name: "ProcessingStartedAt", table: "MediaAssets");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class MediaProcessingTiming : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<TimeSpan>(
name: "ProcessingDuration",
table: "MediaAssets",
type: "interval",
nullable: true
);
migrationBuilder.AddColumn<DateTimeOffset>(
name: "ProcessingStartedAt",
table: "MediaAssets",
type: "timestamp with time zone",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "ProcessingDuration", table: "MediaAssets");
migrationBuilder.DropColumn(name: "ProcessingStartedAt", table: "MediaAssets");
}
}
}
@@ -1,28 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowAudience : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "Audience",
table: "Shows",
type: "integer",
nullable: false,
defaultValue: 0
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "Audience", table: "Shows");
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowAudience : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "Audience",
table: "Shows",
type: "integer",
nullable: false,
defaultValue: 0
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "Audience", table: "Shows");
}
}
}
@@ -1,132 +1,132 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddGenres : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Genres",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
Slug = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
SortOrder = table.Column<int>(type: "integer", nullable: false),
IsSystem = table.Column<bool>(type: "boolean", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Genres", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "GenreAliases",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
GenreId = table.Column<Guid>(type: "uuid", nullable: false),
Value = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_GenreAliases", x => x.Id);
table.ForeignKey(
name: "FK_GenreAliases_Genres_GenreId",
column: x => x.GenreId,
principalTable: "Genres",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ShowGenres",
columns: table => new
{
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
GenreId = table.Column<Guid>(type: "uuid", nullable: false),
IsPrimary = table.Column<bool>(type: "boolean", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ShowGenres", x => new { x.ShowId, x.GenreId });
table.ForeignKey(
name: "FK_ShowGenres_Genres_GenreId",
column: x => x.GenreId,
principalTable: "Genres",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict
);
table.ForeignKey(
name: "FK_ShowGenres_Shows_ShowId",
column: x => x.ShowId,
principalTable: "Shows",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_GenreAliases_GenreId",
table: "GenreAliases",
column: "GenreId"
);
migrationBuilder.CreateIndex(
name: "IX_GenreAliases_Value",
table: "GenreAliases",
column: "Value",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_Genres_Slug",
table: "Genres",
column: "Slug",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_ShowGenres_GenreId",
table: "ShowGenres",
column: "GenreId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "GenreAliases");
migrationBuilder.DropTable(name: "ShowGenres");
migrationBuilder.DropTable(name: "Genres");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddGenres : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Genres",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
Slug = table.Column<string>(
type: "character varying(64)",
maxLength: 64,
nullable: false
),
SortOrder = table.Column<int>(type: "integer", nullable: false),
IsSystem = table.Column<bool>(type: "boolean", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Genres", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "GenreAliases",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
GenreId = table.Column<Guid>(type: "uuid", nullable: false),
Value = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_GenreAliases", x => x.Id);
table.ForeignKey(
name: "FK_GenreAliases_Genres_GenreId",
column: x => x.GenreId,
principalTable: "Genres",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ShowGenres",
columns: table => new
{
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
GenreId = table.Column<Guid>(type: "uuid", nullable: false),
IsPrimary = table.Column<bool>(type: "boolean", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ShowGenres", x => new { x.ShowId, x.GenreId });
table.ForeignKey(
name: "FK_ShowGenres_Genres_GenreId",
column: x => x.GenreId,
principalTable: "Genres",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict
);
table.ForeignKey(
name: "FK_ShowGenres_Shows_ShowId",
column: x => x.ShowId,
principalTable: "Shows",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_GenreAliases_GenreId",
table: "GenreAliases",
column: "GenreId"
);
migrationBuilder.CreateIndex(
name: "IX_GenreAliases_Value",
table: "GenreAliases",
column: "Value",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_Genres_Slug",
table: "Genres",
column: "Slug",
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_ShowGenres_GenreId",
table: "ShowGenres",
column: "GenreId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "GenreAliases");
migrationBuilder.DropTable(name: "ShowGenres");
migrationBuilder.DropTable(name: "Genres");
}
}
}
@@ -1,98 +1,98 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddCollections : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Collections",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Description = table.Column<string>(
type: "character varying(2048)",
maxLength: 2048,
nullable: true
),
PosterImageId = table.Column<Guid>(type: "uuid", nullable: true),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Collections", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "CollectionItems",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CollectionId = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_CollectionItems", x => x.Id);
table.ForeignKey(
name: "FK_CollectionItems_Collections_CollectionId",
column: x => x.CollectionId,
principalTable: "Collections",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
table.ForeignKey(
name: "FK_CollectionItems_Shows_ShowId",
column: x => x.ShowId,
principalTable: "Shows",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_CollectionItems_CollectionId_Position",
table: "CollectionItems",
columns: new[] { "CollectionId", "Position" }
);
migrationBuilder.CreateIndex(
name: "IX_CollectionItems_CollectionId_ShowId",
table: "CollectionItems",
columns: new[] { "CollectionId", "ShowId" },
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_CollectionItems_ShowId",
table: "CollectionItems",
column: "ShowId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "CollectionItems");
migrationBuilder.DropTable(name: "Collections");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddCollections : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Collections",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Description = table.Column<string>(
type: "character varying(2048)",
maxLength: 2048,
nullable: true
),
PosterImageId = table.Column<Guid>(type: "uuid", nullable: true),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Collections", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "CollectionItems",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CollectionId = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_CollectionItems", x => x.Id);
table.ForeignKey(
name: "FK_CollectionItems_Collections_CollectionId",
column: x => x.CollectionId,
principalTable: "Collections",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
table.ForeignKey(
name: "FK_CollectionItems_Shows_ShowId",
column: x => x.ShowId,
principalTable: "Shows",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_CollectionItems_CollectionId_Position",
table: "CollectionItems",
columns: new[] { "CollectionId", "Position" }
);
migrationBuilder.CreateIndex(
name: "IX_CollectionItems_CollectionId_ShowId",
table: "CollectionItems",
columns: new[] { "CollectionId", "ShowId" },
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_CollectionItems_ShowId",
table: "CollectionItems",
column: "ShowId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "CollectionItems");
migrationBuilder.DropTable(name: "Collections");
}
}
}
@@ -1,100 +1,100 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddGroups : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Groups",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Description = table.Column<string>(
type: "character varying(2048)",
maxLength: 2048,
nullable: true
),
FilterJson = table.Column<string>(type: "jsonb", nullable: true),
ItemCount = table.Column<int>(type: "integer", nullable: false),
UnitCount = table.Column<int>(type: "integer", nullable: false),
TotalDuration = table.Column<TimeSpan>(type: "interval", nullable: false),
StatsComputedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Groups", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "GroupItems",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
GroupId = table.Column<Guid>(type: "uuid", nullable: false),
ElementKind = table.Column<int>(type: "integer", nullable: false),
ElementId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_GroupItems", x => x.Id);
table.ForeignKey(
name: "FK_GroupItems_Groups_GroupId",
column: x => x.GroupId,
principalTable: "Groups",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_GroupItems_ElementKind_ElementId",
table: "GroupItems",
columns: new[] { "ElementKind", "ElementId" }
);
migrationBuilder.CreateIndex(
name: "IX_GroupItems_GroupId_ElementKind_ElementId",
table: "GroupItems",
columns: new[] { "GroupId", "ElementKind", "ElementId" },
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_GroupItems_GroupId_Position",
table: "GroupItems",
columns: new[] { "GroupId", "Position" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "GroupItems");
migrationBuilder.DropTable(name: "Groups");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddGroups : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Groups",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Description = table.Column<string>(
type: "character varying(2048)",
maxLength: 2048,
nullable: true
),
FilterJson = table.Column<string>(type: "jsonb", nullable: true),
ItemCount = table.Column<int>(type: "integer", nullable: false),
UnitCount = table.Column<int>(type: "integer", nullable: false),
TotalDuration = table.Column<TimeSpan>(type: "interval", nullable: false),
StatsComputedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_Groups", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "GroupItems",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
GroupId = table.Column<Guid>(type: "uuid", nullable: false),
ElementKind = table.Column<int>(type: "integer", nullable: false),
ElementId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_GroupItems", x => x.Id);
table.ForeignKey(
name: "FK_GroupItems_Groups_GroupId",
column: x => x.GroupId,
principalTable: "Groups",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_GroupItems_ElementKind_ElementId",
table: "GroupItems",
columns: new[] { "ElementKind", "ElementId" }
);
migrationBuilder.CreateIndex(
name: "IX_GroupItems_GroupId_ElementKind_ElementId",
table: "GroupItems",
columns: new[] { "GroupId", "ElementKind", "ElementId" },
unique: true
);
migrationBuilder.CreateIndex(
name: "IX_GroupItems_GroupId_Position",
table: "GroupItems",
columns: new[] { "GroupId", "Position" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "GroupItems");
migrationBuilder.DropTable(name: "Groups");
}
}
}
@@ -1,224 +1,224 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddScheduleTemplate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<TimeOnly>(
name: "DayStartTime",
table: "Channels",
type: "time without time zone",
nullable: false,
defaultValue: new TimeOnly(0, 0, 0)
);
migrationBuilder.AddColumn<int>(
name: "Number",
table: "Channels",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "TemplateId",
table: "Channels",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "UtcOffsetMinutes",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.CreateTable(
name: "ScheduleTemplates",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
FallbackGroupId = table.Column<Guid>(type: "uuid", nullable: true),
Revision = table.Column<int>(type: "integer", nullable: false),
AppliedRevision = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_ScheduleTemplates", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "GridLayers",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
TemplateId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
Priority = table.Column<int>(type: "integer", nullable: false),
ApplicabilityJson = table.Column<string>(type: "jsonb", nullable: true),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
IsBackground = table.Column<bool>(type: "boolean", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_GridLayers", x => x.Id);
table.ForeignKey(
name: "FK_GridLayers_ScheduleTemplates_TemplateId",
column: x => x.TemplateId,
principalTable: "ScheduleTemplates",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "Slots",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
LayerId = table.Column<Guid>(type: "uuid", nullable: false),
Weekday = table.Column<int>(type: "integer", nullable: true),
TargetStart = table.Column<TimeOnly>(
type: "time without time zone",
nullable: false
),
TargetDurationMinutes = table.Column<int>(type: "integer", nullable: false),
Title = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Daypart = table.Column<int>(type: "integer", nullable: false),
SlotKind = table.Column<int>(type: "integer", nullable: false),
GroupId = table.Column<Guid>(type: "uuid", nullable: true),
StrategyJson = table.Column<string>(type: "jsonb", nullable: true),
RepeatSourceJson = table.Column<string>(type: "jsonb", nullable: true),
BlockMode = table.Column<int>(type: "integer", nullable: false),
BlockValue = table.Column<int>(type: "integer", nullable: false),
OverflowPolicy = table.Column<int>(type: "integer", nullable: false),
IsAnchor = table.Column<bool>(type: "boolean", nullable: false),
MaxDriftMinutes = table.Column<int>(type: "integer", nullable: false),
SnapToMinutes = table.Column<int>(type: "integer", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_Slots", x => x.Id);
table.ForeignKey(
name: "FK_Slots_GridLayers_LayerId",
column: x => x.LayerId,
principalTable: "GridLayers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
table.ForeignKey(
name: "FK_Slots_Groups_GroupId",
column: x => x.GroupId,
principalTable: "Groups",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict
);
}
);
migrationBuilder.CreateTable(
name: "SlotStates",
columns: table => new
{
SlotId = table.Column<Guid>(type: "uuid", nullable: false),
CurrentElementKind = table.Column<int>(type: "integer", nullable: true),
CurrentElementId = table.Column<Guid>(type: "uuid", nullable: true),
NextUnitIndex = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_SlotStates", x => x.SlotId);
table.ForeignKey(
name: "FK_SlotStates_Slots_SlotId",
column: x => x.SlotId,
principalTable: "Slots",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_Channels_Number",
table: "Channels",
column: "Number",
unique: true,
filter: "\"Number\" IS NOT NULL"
);
migrationBuilder.CreateIndex(
name: "IX_GridLayers_TemplateId_Priority",
table: "GridLayers",
columns: new[] { "TemplateId", "Priority" }
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleTemplates_ChannelId",
table: "ScheduleTemplates",
column: "ChannelId"
);
migrationBuilder.CreateIndex(
name: "IX_Slots_GroupId",
table: "Slots",
column: "GroupId"
);
migrationBuilder.CreateIndex(
name: "IX_Slots_LayerId_TargetStart",
table: "Slots",
columns: new[] { "LayerId", "TargetStart" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "SlotStates");
migrationBuilder.DropTable(name: "Slots");
migrationBuilder.DropTable(name: "GridLayers");
migrationBuilder.DropTable(name: "ScheduleTemplates");
migrationBuilder.DropIndex(name: "IX_Channels_Number", table: "Channels");
migrationBuilder.DropColumn(name: "DayStartTime", table: "Channels");
migrationBuilder.DropColumn(name: "Number", table: "Channels");
migrationBuilder.DropColumn(name: "TemplateId", table: "Channels");
migrationBuilder.DropColumn(name: "UtcOffsetMinutes", table: "Channels");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddScheduleTemplate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<TimeOnly>(
name: "DayStartTime",
table: "Channels",
type: "time without time zone",
nullable: false,
defaultValue: new TimeOnly(0, 0, 0)
);
migrationBuilder.AddColumn<int>(
name: "Number",
table: "Channels",
type: "integer",
nullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "TemplateId",
table: "Channels",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<int>(
name: "UtcOffsetMinutes",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.CreateTable(
name: "ScheduleTemplates",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
FallbackGroupId = table.Column<Guid>(type: "uuid", nullable: true),
Revision = table.Column<int>(type: "integer", nullable: false),
AppliedRevision = table.Column<int>(type: "integer", nullable: false),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_ScheduleTemplates", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "GridLayers",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
TemplateId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
Priority = table.Column<int>(type: "integer", nullable: false),
ApplicabilityJson = table.Column<string>(type: "jsonb", nullable: true),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
IsBackground = table.Column<bool>(type: "boolean", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_GridLayers", x => x.Id);
table.ForeignKey(
name: "FK_GridLayers_ScheduleTemplates_TemplateId",
column: x => x.TemplateId,
principalTable: "ScheduleTemplates",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "Slots",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
LayerId = table.Column<Guid>(type: "uuid", nullable: false),
Weekday = table.Column<int>(type: "integer", nullable: true),
TargetStart = table.Column<TimeOnly>(
type: "time without time zone",
nullable: false
),
TargetDurationMinutes = table.Column<int>(type: "integer", nullable: false),
Title = table.Column<string>(
type: "character varying(256)",
maxLength: 256,
nullable: false
),
Daypart = table.Column<int>(type: "integer", nullable: false),
SlotKind = table.Column<int>(type: "integer", nullable: false),
GroupId = table.Column<Guid>(type: "uuid", nullable: true),
StrategyJson = table.Column<string>(type: "jsonb", nullable: true),
RepeatSourceJson = table.Column<string>(type: "jsonb", nullable: true),
BlockMode = table.Column<int>(type: "integer", nullable: false),
BlockValue = table.Column<int>(type: "integer", nullable: false),
OverflowPolicy = table.Column<int>(type: "integer", nullable: false),
IsAnchor = table.Column<bool>(type: "boolean", nullable: false),
MaxDriftMinutes = table.Column<int>(type: "integer", nullable: false),
SnapToMinutes = table.Column<int>(type: "integer", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_Slots", x => x.Id);
table.ForeignKey(
name: "FK_Slots_GridLayers_LayerId",
column: x => x.LayerId,
principalTable: "GridLayers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
table.ForeignKey(
name: "FK_Slots_Groups_GroupId",
column: x => x.GroupId,
principalTable: "Groups",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict
);
}
);
migrationBuilder.CreateTable(
name: "SlotStates",
columns: table => new
{
SlotId = table.Column<Guid>(type: "uuid", nullable: false),
CurrentElementKind = table.Column<int>(type: "integer", nullable: true),
CurrentElementId = table.Column<Guid>(type: "uuid", nullable: true),
NextUnitIndex = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_SlotStates", x => x.SlotId);
table.ForeignKey(
name: "FK_SlotStates_Slots_SlotId",
column: x => x.SlotId,
principalTable: "Slots",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_Channels_Number",
table: "Channels",
column: "Number",
unique: true,
filter: "\"Number\" IS NOT NULL"
);
migrationBuilder.CreateIndex(
name: "IX_GridLayers_TemplateId_Priority",
table: "GridLayers",
columns: new[] { "TemplateId", "Priority" }
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleTemplates_ChannelId",
table: "ScheduleTemplates",
column: "ChannelId"
);
migrationBuilder.CreateIndex(
name: "IX_Slots_GroupId",
table: "Slots",
column: "GroupId"
);
migrationBuilder.CreateIndex(
name: "IX_Slots_LayerId_TargetStart",
table: "Slots",
columns: new[] { "LayerId", "TargetStart" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "SlotStates");
migrationBuilder.DropTable(name: "Slots");
migrationBuilder.DropTable(name: "GridLayers");
migrationBuilder.DropTable(name: "ScheduleTemplates");
migrationBuilder.DropIndex(name: "IX_Channels_Number", table: "Channels");
migrationBuilder.DropColumn(name: "DayStartTime", table: "Channels");
migrationBuilder.DropColumn(name: "Number", table: "Channels");
migrationBuilder.DropColumn(name: "TemplateId", table: "Channels");
migrationBuilder.DropColumn(name: "UtcOffsetMinutes", table: "Channels");
}
}
}
@@ -1,59 +1,59 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ScheduleEntryTrace : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId",
table: "ScheduleEntries"
);
migrationBuilder.AddColumn<Guid>(
name: "SlotId",
table: "ScheduleEntries",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "TraceJson",
table: "ScheduleEntries",
type: "jsonb",
nullable: true
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId_StartsAtUtc",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "ShowId", "StartsAtUtc" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId_StartsAtUtc",
table: "ScheduleEntries"
);
migrationBuilder.DropColumn(name: "SlotId", table: "ScheduleEntries");
migrationBuilder.DropColumn(name: "TraceJson", table: "ScheduleEntries");
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "ShowId" }
);
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ScheduleEntryTrace : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId",
table: "ScheduleEntries"
);
migrationBuilder.AddColumn<Guid>(
name: "SlotId",
table: "ScheduleEntries",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<string>(
name: "TraceJson",
table: "ScheduleEntries",
type: "jsonb",
nullable: true
);
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId_StartsAtUtc",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "ShowId", "StartsAtUtc" }
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId_StartsAtUtc",
table: "ScheduleEntries"
);
migrationBuilder.DropColumn(name: "SlotId", table: "ScheduleEntries");
migrationBuilder.DropColumn(name: "TraceJson", table: "ScheduleEntries");
migrationBuilder.CreateIndex(
name: "IX_ScheduleEntries_ChannelId_ShowId",
table: "ScheduleEntries",
columns: new[] { "ChannelId", "ShowId" }
);
}
}
}
@@ -1,219 +1,219 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class DropLegacyRotation : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelAd");
migrationBuilder.DropTable(name: "ChannelShowHour");
migrationBuilder.DropTable(name: "OverrideShow");
migrationBuilder.DropTable(name: "ChannelShow");
migrationBuilder.DropTable(name: "ProgrammingOverride");
migrationBuilder.DropColumn(name: "AdInsertion", table: "Channels");
migrationBuilder.DropColumn(name: "AdsPerBreak", table: "Channels");
migrationBuilder.DropColumn(name: "NextAdIndex", table: "Channels");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "AdInsertion",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "AdsPerBreak",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "NextAdIndex",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.CreateTable(
name: "ChannelAd",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelAd", x => x.Id);
table.ForeignKey(
name: "FK_ChannelAd_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ChannelShow",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
BlockMode = table.Column<int>(type: "integer", nullable: false),
BlockValue = table.Column<int>(type: "integer", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
NextEpisodeIndex = table.Column<int>(type: "integer", nullable: false),
PreferredWeightMultiplier = table.Column<int>(
type: "integer",
nullable: false,
defaultValue: 3
),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelShow", x => x.Id);
table.ForeignKey(
name: "FK_ChannelShow_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ProgrammingOverride",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
DayOfWeek = table.Column<int>(type: "integer", nullable: true),
EndMinute = table.Column<int>(type: "integer", nullable: true),
EndsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
Mode = table.Column<int>(type: "integer", nullable: false),
Recurrence = table.Column<int>(type: "integer", nullable: false),
StartMinute = table.Column<int>(type: "integer", nullable: true),
StartsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
},
constraints: table =>
{
table.PrimaryKey("PK_ProgrammingOverride", x => x.Id);
table.ForeignKey(
name: "FK_ProgrammingOverride_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ChannelShowHour",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelShowId = table.Column<Guid>(type: "uuid", nullable: false),
EndHour = table.Column<int>(type: "integer", nullable: false),
StartHour = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelShowHour", x => x.Id);
table.ForeignKey(
name: "FK_ChannelShowHour_ChannelShow_ChannelShowId",
column: x => x.ChannelShowId,
principalTable: "ChannelShow",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "OverrideShow",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ProgrammingOverrideId = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_OverrideShow", x => x.Id);
table.ForeignKey(
name: "FK_OverrideShow_ProgrammingOverride_ProgrammingOverrideId",
column: x => x.ProgrammingOverrideId,
principalTable: "ProgrammingOverride",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelAd_ChannelId_Position",
table: "ChannelAd",
columns: new[] { "ChannelId", "Position" }
);
migrationBuilder.CreateIndex(
name: "IX_ChannelShow_ChannelId_ShowId",
table: "ChannelShow",
columns: new[] { "ChannelId", "ShowId" }
);
migrationBuilder.CreateIndex(
name: "IX_ChannelShowHour_ChannelShowId",
table: "ChannelShowHour",
column: "ChannelShowId"
);
migrationBuilder.CreateIndex(
name: "IX_OverrideShow_ProgrammingOverrideId",
table: "OverrideShow",
column: "ProgrammingOverrideId"
);
migrationBuilder.CreateIndex(
name: "IX_ProgrammingOverride_ChannelId_StartsAtUtc_EndsAtUtc",
table: "ProgrammingOverride",
columns: new[] { "ChannelId", "StartsAtUtc", "EndsAtUtc" }
);
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class DropLegacyRotation : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "ChannelAd");
migrationBuilder.DropTable(name: "ChannelShowHour");
migrationBuilder.DropTable(name: "OverrideShow");
migrationBuilder.DropTable(name: "ChannelShow");
migrationBuilder.DropTable(name: "ProgrammingOverride");
migrationBuilder.DropColumn(name: "AdInsertion", table: "Channels");
migrationBuilder.DropColumn(name: "AdsPerBreak", table: "Channels");
migrationBuilder.DropColumn(name: "NextAdIndex", table: "Channels");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "AdInsertion",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "AdsPerBreak",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<int>(
name: "NextAdIndex",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.CreateTable(
name: "ChannelAd",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
MediaAssetId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelAd", x => x.Id);
table.ForeignKey(
name: "FK_ChannelAd_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ChannelShow",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
BlockMode = table.Column<int>(type: "integer", nullable: false),
BlockValue = table.Column<int>(type: "integer", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
NextEpisodeIndex = table.Column<int>(type: "integer", nullable: false),
PreferredWeightMultiplier = table.Column<int>(
type: "integer",
nullable: false,
defaultValue: 3
),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelShow", x => x.Id);
table.ForeignKey(
name: "FK_ChannelShow_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ProgrammingOverride",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
DayOfWeek = table.Column<int>(type: "integer", nullable: true),
EndMinute = table.Column<int>(type: "integer", nullable: true),
EndsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
Mode = table.Column<int>(type: "integer", nullable: false),
Recurrence = table.Column<int>(type: "integer", nullable: false),
StartMinute = table.Column<int>(type: "integer", nullable: true),
StartsAtUtc = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: true
),
},
constraints: table =>
{
table.PrimaryKey("PK_ProgrammingOverride", x => x.Id);
table.ForeignKey(
name: "FK_ProgrammingOverride_Channels_ChannelId",
column: x => x.ChannelId,
principalTable: "Channels",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "ChannelShowHour",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelShowId = table.Column<Guid>(type: "uuid", nullable: false),
EndHour = table.Column<int>(type: "integer", nullable: false),
StartHour = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelShowHour", x => x.Id);
table.ForeignKey(
name: "FK_ChannelShowHour_ChannelShow_ChannelShowId",
column: x => x.ChannelShowId,
principalTable: "ChannelShow",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateTable(
name: "OverrideShow",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ProgrammingOverrideId = table.Column<Guid>(type: "uuid", nullable: false),
ShowId = table.Column<Guid>(type: "uuid", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_OverrideShow", x => x.Id);
table.ForeignKey(
name: "FK_OverrideShow_ProgrammingOverride_ProgrammingOverrideId",
column: x => x.ProgrammingOverrideId,
principalTable: "ProgrammingOverride",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_ChannelAd_ChannelId_Position",
table: "ChannelAd",
columns: new[] { "ChannelId", "Position" }
);
migrationBuilder.CreateIndex(
name: "IX_ChannelShow_ChannelId_ShowId",
table: "ChannelShow",
columns: new[] { "ChannelId", "ShowId" }
);
migrationBuilder.CreateIndex(
name: "IX_ChannelShowHour_ChannelShowId",
table: "ChannelShowHour",
column: "ChannelShowId"
);
migrationBuilder.CreateIndex(
name: "IX_OverrideShow_ProgrammingOverrideId",
table: "OverrideShow",
column: "ProgrammingOverrideId"
);
migrationBuilder.CreateIndex(
name: "IX_ProgrammingOverride_ChannelId_StartsAtUtc_EndsAtUtc",
table: "ProgrammingOverride",
columns: new[] { "ChannelId", "StartsAtUtc", "EndsAtUtc" }
);
}
}
}
@@ -1,125 +1,125 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddJunctionTemplates : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "JunctionAfterId",
table: "Slots",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "JunctionBetweenId",
table: "Slots",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "DefaultJunctionId",
table: "ScheduleTemplates",
type: "uuid",
nullable: true
);
migrationBuilder.CreateTable(
name: "JunctionTemplates",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_JunctionTemplates", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "JunctionElements",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
JunctionTemplateId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
Kind = table.Column<int>(type: "integer", nullable: false),
GroupId = table.Column<Guid>(type: "uuid", nullable: true),
BumperTemplateId = table.Column<Guid>(type: "uuid", nullable: true),
AmountMode = table.Column<int>(type: "integer", nullable: false),
AmountValue = table.Column<int>(type: "integer", nullable: false),
IsRequired = table.Column<bool>(type: "boolean", nullable: false),
ConditionsJson = table.Column<string>(type: "jsonb", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_JunctionElements", x => x.Id);
table.ForeignKey(
name: "FK_JunctionElements_Groups_GroupId",
column: x => x.GroupId,
principalTable: "Groups",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict
);
table.ForeignKey(
name: "FK_JunctionElements_JunctionTemplates_JunctionTemplateId",
column: x => x.JunctionTemplateId,
principalTable: "JunctionTemplates",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_JunctionElements_GroupId",
table: "JunctionElements",
column: "GroupId"
);
migrationBuilder.CreateIndex(
name: "IX_JunctionElements_JunctionTemplateId_Position",
table: "JunctionElements",
columns: new[] { "JunctionTemplateId", "Position" }
);
migrationBuilder.CreateIndex(
name: "IX_JunctionTemplates_ChannelId",
table: "JunctionTemplates",
column: "ChannelId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "JunctionElements");
migrationBuilder.DropTable(name: "JunctionTemplates");
migrationBuilder.DropColumn(name: "JunctionAfterId", table: "Slots");
migrationBuilder.DropColumn(name: "JunctionBetweenId", table: "Slots");
migrationBuilder.DropColumn(name: "DefaultJunctionId", table: "ScheduleTemplates");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddJunctionTemplates : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "JunctionAfterId",
table: "Slots",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "JunctionBetweenId",
table: "Slots",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<Guid>(
name: "DefaultJunctionId",
table: "ScheduleTemplates",
type: "uuid",
nullable: true
);
migrationBuilder.CreateTable(
name: "JunctionTemplates",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ChannelId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(
type: "character varying(128)",
maxLength: 128,
nullable: false
),
CreatedAt = table.Column<DateTimeOffset>(
type: "timestamp with time zone",
nullable: false
),
},
constraints: table =>
{
table.PrimaryKey("PK_JunctionTemplates", x => x.Id);
}
);
migrationBuilder.CreateTable(
name: "JunctionElements",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
JunctionTemplateId = table.Column<Guid>(type: "uuid", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
Kind = table.Column<int>(type: "integer", nullable: false),
GroupId = table.Column<Guid>(type: "uuid", nullable: true),
BumperTemplateId = table.Column<Guid>(type: "uuid", nullable: true),
AmountMode = table.Column<int>(type: "integer", nullable: false),
AmountValue = table.Column<int>(type: "integer", nullable: false),
IsRequired = table.Column<bool>(type: "boolean", nullable: false),
ConditionsJson = table.Column<string>(type: "jsonb", nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_JunctionElements", x => x.Id);
table.ForeignKey(
name: "FK_JunctionElements_Groups_GroupId",
column: x => x.GroupId,
principalTable: "Groups",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict
);
table.ForeignKey(
name: "FK_JunctionElements_JunctionTemplates_JunctionTemplateId",
column: x => x.JunctionTemplateId,
principalTable: "JunctionTemplates",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade
);
}
);
migrationBuilder.CreateIndex(
name: "IX_JunctionElements_GroupId",
table: "JunctionElements",
column: "GroupId"
);
migrationBuilder.CreateIndex(
name: "IX_JunctionElements_JunctionTemplateId_Position",
table: "JunctionElements",
columns: new[] { "JunctionTemplateId", "Position" }
);
migrationBuilder.CreateIndex(
name: "IX_JunctionTemplates_ChannelId",
table: "JunctionTemplates",
column: "ChannelId"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "JunctionElements");
migrationBuilder.DropTable(name: "JunctionTemplates");
migrationBuilder.DropColumn(name: "JunctionAfterId", table: "Slots");
migrationBuilder.DropColumn(name: "JunctionBetweenId", table: "Slots");
migrationBuilder.DropColumn(name: "DefaultJunctionId", table: "ScheduleTemplates");
}
}
}
@@ -1,64 +1,64 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class DropDeadBumperSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// Значение 0 (прежняя «ротация») из перечисления убрано: курсора ротации больше нет,
// и выбор молча вырождался в случайный. Переводим такие каналы на выбор по весам.
migrationBuilder.Sql(
"""UPDATE "Channels" SET "BumperSelection" = 3 WHERE "BumperSelection" = 0;"""
);
migrationBuilder.DropColumn(name: "BumperEpisodeChangeChance", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMinIntervalMinutes", table: "Channels");
migrationBuilder.DropColumn(name: "BumperShowChangeChance", table: "Channels");
migrationBuilder.DropColumn(name: "NextBumperIndex", table: "Channels");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<double>(
name: "BumperEpisodeChangeChance",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 0.0
);
migrationBuilder.AddColumn<int>(
name: "BumperMinIntervalMinutes",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<double>(
name: "BumperShowChangeChance",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 0.0
);
migrationBuilder.AddColumn<int>(
name: "NextBumperIndex",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class DropDeadBumperSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// Значение 0 (прежняя «ротация») из перечисления убрано: курсора ротации больше нет,
// и выбор молча вырождался в случайный. Переводим такие каналы на выбор по весам.
migrationBuilder.Sql(
"""UPDATE "Channels" SET "BumperSelection" = 3 WHERE "BumperSelection" = 0;"""
);
migrationBuilder.DropColumn(name: "BumperEpisodeChangeChance", table: "Channels");
migrationBuilder.DropColumn(name: "BumperMinIntervalMinutes", table: "Channels");
migrationBuilder.DropColumn(name: "BumperShowChangeChance", table: "Channels");
migrationBuilder.DropColumn(name: "NextBumperIndex", table: "Channels");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<double>(
name: "BumperEpisodeChangeChance",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 0.0
);
migrationBuilder.AddColumn<int>(
name: "BumperMinIntervalMinutes",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<double>(
name: "BumperShowChangeChance",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 0.0
);
migrationBuilder.AddColumn<int>(
name: "NextBumperIndex",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
}
}
}
@@ -1,27 +1,27 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class TemplatePlanningRules : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "RulesJson",
table: "ScheduleTemplates",
type: "jsonb",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "RulesJson", table: "ScheduleTemplates");
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class TemplatePlanningRules : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "RulesJson",
table: "ScheduleTemplates",
type: "jsonb",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "RulesJson", table: "ScheduleTemplates");
}
}
}
@@ -1,68 +1,68 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ChannelViewerSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<double>(
name: "AnalogFilterStrength",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 0.0
);
migrationBuilder.AddColumn<int>(
name: "LogoCorner",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<Guid>(
name: "LogoImageId",
table: "Channels",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<double>(
name: "LogoOpacity",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 0.0
);
migrationBuilder.AddColumn<bool>(
name: "ShowClock",
table: "Channels",
type: "boolean",
nullable: false,
defaultValue: false
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "AnalogFilterStrength", table: "Channels");
migrationBuilder.DropColumn(name: "LogoCorner", table: "Channels");
migrationBuilder.DropColumn(name: "LogoImageId", table: "Channels");
migrationBuilder.DropColumn(name: "LogoOpacity", table: "Channels");
migrationBuilder.DropColumn(name: "ShowClock", table: "Channels");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ChannelViewerSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<double>(
name: "AnalogFilterStrength",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 0.0
);
migrationBuilder.AddColumn<int>(
name: "LogoCorner",
table: "Channels",
type: "integer",
nullable: false,
defaultValue: 0
);
migrationBuilder.AddColumn<Guid>(
name: "LogoImageId",
table: "Channels",
type: "uuid",
nullable: true
);
migrationBuilder.AddColumn<double>(
name: "LogoOpacity",
table: "Channels",
type: "double precision",
nullable: false,
defaultValue: 0.0
);
migrationBuilder.AddColumn<bool>(
name: "ShowClock",
table: "Channels",
type: "boolean",
nullable: false,
defaultValue: false
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "AnalogFilterStrength", table: "Channels");
migrationBuilder.DropColumn(name: "LogoCorner", table: "Channels");
migrationBuilder.DropColumn(name: "LogoImageId", table: "Channels");
migrationBuilder.DropColumn(name: "LogoOpacity", table: "Channels");
migrationBuilder.DropColumn(name: "ShowClock", table: "Channels");
}
}
}
@@ -1,28 +1,28 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ScheduleEntryCollection : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "CollectionId",
table: "ScheduleEntries",
type: "uuid",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "CollectionId", table: "ScheduleEntries");
}
}
}
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ScheduleEntryCollection : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "CollectionId",
table: "ScheduleEntries",
type: "uuid",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "CollectionId", table: "ScheduleEntries");
}
}
}
@@ -1,38 +1,38 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowAudienceMpaa : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "Audience",
table: "Shows",
type: "integer",
nullable: true,
oldClrType: typeof(int),
oldType: "integer"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "Audience",
table: "Shows",
type: "integer",
nullable: false,
defaultValue: 0,
oldClrType: typeof(int),
oldType: "integer",
oldNullable: true
);
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TeleWave.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class ShowAudienceMpaa : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "Audience",
table: "Shows",
type: "integer",
nullable: true,
oldClrType: typeof(int),
oldType: "integer"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "Audience",
table: "Shows",
type: "integer",
nullable: false,
defaultValue: 0,
oldClrType: typeof(int),
oldType: "integer",
oldNullable: true
);
}
}
}
@@ -1,83 +1,83 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Domain.Auth;
using TeleWave.Domain.Broadcast;
using TeleWave.Domain.Images;
using TeleWave.Domain.Library;
using TeleWave.Domain.Media;
using TeleWave.Domain.Programming;
using TeleWave.Domain.Settings;
using TeleWave.Infrastructure.Identity;
namespace TeleWave.Infrastructure.Persistence;
/// <summary>
/// Корневой DbContext приложения: Identity-схема (пользователи/роли) + сущности домена
/// (добавляются по мере реализации фич).
/// </summary>
public class AppDbContext(DbContextOptions<AppDbContext> options)
: IdentityDbContext<AppUser, AppRole, Guid>(options),
IAppDbContext
{
public DbSet<RefreshToken> RefreshTokens => Set<RefreshToken>();
public DbSet<MediaAsset> MediaAssets => Set<MediaAsset>();
public DbSet<Show> Shows => Set<Show>();
public DbSet<Genre> Genres => Set<Genre>();
public DbSet<GenreAlias> GenreAliases => Set<GenreAlias>();
public DbSet<ShowGenre> ShowGenres => Set<ShowGenre>();
public DbSet<Collection> Collections => Set<Collection>();
public DbSet<CollectionItem> CollectionItems => Set<CollectionItem>();
public DbSet<Group> Groups => Set<Group>();
public DbSet<GroupItem> GroupItems => Set<GroupItem>();
public DbSet<ScheduleTemplate> ScheduleTemplates => Set<ScheduleTemplate>();
public DbSet<GridLayer> GridLayers => Set<GridLayer>();
public DbSet<Slot> Slots => Set<Slot>();
public DbSet<SlotState> SlotStates => Set<SlotState>();
public DbSet<JunctionTemplate> JunctionTemplates => Set<JunctionTemplate>();
public DbSet<JunctionElement> JunctionElements => Set<JunctionElement>();
public DbSet<Channel> Channels => Set<Channel>();
public DbSet<ScheduleEntry> ScheduleEntries => Set<ScheduleEntry>();
public DbSet<BumperTextVariant> BumperTextVariants => Set<BumperTextVariant>();
public DbSet<BumperAsset> BumperAssets => Set<BumperAsset>();
public DbSet<AppSetting> AppSettings => Set<AppSetting>();
public DbSet<Image> Images => Set<Image>();
public Task<IDbContextTransaction> BeginTransactionAsync(CancellationToken cancellationToken) =>
Database.BeginTransactionAsync(cancellationToken);
public Task AcquireChannelLockAsync(Guid channelId, CancellationToken cancellationToken)
{
// pg_advisory_xact_lock(bigint) освобождается автоматически при завершении транзакции.
// Ключ — стабильный int64 из GUID канала; коллизии между каналами лишь сериализуют их генерацию,
// корректности не нарушают.
var key = BitConverter.ToInt64(channelId.ToByteArray());
return Database.ExecuteSqlAsync($"SELECT pg_advisory_xact_lock({key})", cancellationToken);
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
// Guid-ключи доменных сущностей мы задаём сами в фабриках. Без этого EF считает выставленный
// ключ признаком уже существующей строки и при добавлении дочерней сущности через коллекцию
// отслеживаемого родителя (напр. show.AddEpisode) делает UPDATE вместо INSERT → «affected 0».
foreach (var entityType in builder.Model.GetEntityTypes())
{
if (
entityType.ClrType.Namespace?.StartsWith(
"TeleWave.Domain",
StringComparison.Ordinal
) != true
)
continue;
var idProperty = entityType.FindProperty("Id");
if (idProperty is not null && idProperty.ClrType == typeof(Guid))
idProperty.ValueGenerated = ValueGenerated.Never;
}
}
}
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Domain.Auth;
using TeleWave.Domain.Broadcast;
using TeleWave.Domain.Images;
using TeleWave.Domain.Library;
using TeleWave.Domain.Media;
using TeleWave.Domain.Programming;
using TeleWave.Domain.Settings;
using TeleWave.Infrastructure.Identity;
namespace TeleWave.Infrastructure.Persistence;
/// <summary>
/// Корневой DbContext приложения: Identity-схема (пользователи/роли) + сущности домена
/// (добавляются по мере реализации фич).
/// </summary>
public class AppDbContext(DbContextOptions<AppDbContext> options)
: IdentityDbContext<AppUser, AppRole, Guid>(options),
IAppDbContext
{
public DbSet<RefreshToken> RefreshTokens => Set<RefreshToken>();
public DbSet<MediaAsset> MediaAssets => Set<MediaAsset>();
public DbSet<Show> Shows => Set<Show>();
public DbSet<Genre> Genres => Set<Genre>();
public DbSet<GenreAlias> GenreAliases => Set<GenreAlias>();
public DbSet<ShowGenre> ShowGenres => Set<ShowGenre>();
public DbSet<Collection> Collections => Set<Collection>();
public DbSet<CollectionItem> CollectionItems => Set<CollectionItem>();
public DbSet<Group> Groups => Set<Group>();
public DbSet<GroupItem> GroupItems => Set<GroupItem>();
public DbSet<ScheduleTemplate> ScheduleTemplates => Set<ScheduleTemplate>();
public DbSet<GridLayer> GridLayers => Set<GridLayer>();
public DbSet<Slot> Slots => Set<Slot>();
public DbSet<SlotState> SlotStates => Set<SlotState>();
public DbSet<JunctionTemplate> JunctionTemplates => Set<JunctionTemplate>();
public DbSet<JunctionElement> JunctionElements => Set<JunctionElement>();
public DbSet<Channel> Channels => Set<Channel>();
public DbSet<ScheduleEntry> ScheduleEntries => Set<ScheduleEntry>();
public DbSet<BumperTextVariant> BumperTextVariants => Set<BumperTextVariant>();
public DbSet<BumperAsset> BumperAssets => Set<BumperAsset>();
public DbSet<AppSetting> AppSettings => Set<AppSetting>();
public DbSet<Image> Images => Set<Image>();
public Task<IDbContextTransaction> BeginTransactionAsync(CancellationToken cancellationToken) =>
Database.BeginTransactionAsync(cancellationToken);
public Task AcquireChannelLockAsync(Guid channelId, CancellationToken cancellationToken)
{
// pg_advisory_xact_lock(bigint) освобождается автоматически при завершении транзакции.
// Ключ — стабильный int64 из GUID канала; коллизии между каналами лишь сериализуют их генерацию,
// корректности не нарушают.
var key = BitConverter.ToInt64(channelId.ToByteArray());
return Database.ExecuteSqlAsync($"SELECT pg_advisory_xact_lock({key})", cancellationToken);
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
// Guid-ключи доменных сущностей мы задаём сами в фабриках. Без этого EF считает выставленный
// ключ признаком уже существующей строки и при добавлении дочерней сущности через коллекцию
// отслеживаемого родителя (напр. show.AddEpisode) делает UPDATE вместо INSERT → «affected 0».
foreach (var entityType in builder.Model.GetEntityTypes())
{
if (
entityType.ClrType.Namespace?.StartsWith(
"TeleWave.Domain",
StringComparison.Ordinal
) != true
)
continue;
var idProperty = entityType.FindProperty("Id");
if (idProperty is not null && idProperty.ClrType == typeof(Guid))
idProperty.ValueGenerated = ValueGenerated.Never;
}
}
}
@@ -1,61 +1,61 @@
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.HasIndex(x => x.Number).IsUnique().HasFilter("\"Number\" IS NOT NULL");
builder
.HasMany(x => x.BumperTemplates)
.WithOne()
.HasForeignKey(t => t.ChannelId)
.OnDelete(DeleteBehavior.Cascade);
builder.Navigation(x => x.BumperTemplates).UsePropertyAccessMode(PropertyAccessMode.Field);
}
}
public class BumperTemplateConfiguration : IEntityTypeConfiguration<BumperTemplate>
{
public void Configure(EntityTypeBuilder<BumperTemplate> builder)
{
builder.HasIndex(x => new { x.ChannelId, x.Position });
builder.Property(x => x.Name).IsRequired().HasMaxLength(64);
builder.Property(x => x.BackgroundColor).IsRequired().HasMaxLength(32);
builder.Property(x => x.BackgroundColor2).IsRequired().HasMaxLength(32);
builder.Property(x => x.AccentColor).IsRequired().HasMaxLength(32);
builder.Property(x => x.TextColor).IsRequired().HasMaxLength(32);
builder.Property(x => x.AudioExtension).HasMaxLength(16);
builder
.HasMany(x => x.Variants)
.WithOne()
.HasForeignKey(v => v.BumperTemplateId)
.OnDelete(DeleteBehavior.Cascade);
builder.Navigation(x => x.Variants).UsePropertyAccessMode(PropertyAccessMode.Field);
}
}
public class BumperTextVariantConfiguration : IEntityTypeConfiguration<BumperTextVariant>
{
public void Configure(EntityTypeBuilder<BumperTextVariant> builder)
{
builder.HasIndex(x => new { x.BumperTemplateId, x.Position });
builder.Property(x => x.Name).IsRequired().HasMaxLength(64);
builder.Property(x => x.NowLabel).IsRequired().HasMaxLength(64);
builder.Property(x => x.NextLabel).IsRequired().HasMaxLength(64);
builder.Property(x => x.Line1).IsRequired().HasMaxLength(120);
builder.Property(x => x.Line2).IsRequired().HasMaxLength(120);
builder.Property(x => x.Weight).HasDefaultValue(BumperTextVariant.DefaultWeight);
}
}
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.HasIndex(x => x.Number).IsUnique().HasFilter("\"Number\" IS NOT NULL");
builder
.HasMany(x => x.BumperTemplates)
.WithOne()
.HasForeignKey(t => t.ChannelId)
.OnDelete(DeleteBehavior.Cascade);
builder.Navigation(x => x.BumperTemplates).UsePropertyAccessMode(PropertyAccessMode.Field);
}
}
public class BumperTemplateConfiguration : IEntityTypeConfiguration<BumperTemplate>
{
public void Configure(EntityTypeBuilder<BumperTemplate> builder)
{
builder.HasIndex(x => new { x.ChannelId, x.Position });
builder.Property(x => x.Name).IsRequired().HasMaxLength(64);
builder.Property(x => x.BackgroundColor).IsRequired().HasMaxLength(32);
builder.Property(x => x.BackgroundColor2).IsRequired().HasMaxLength(32);
builder.Property(x => x.AccentColor).IsRequired().HasMaxLength(32);
builder.Property(x => x.TextColor).IsRequired().HasMaxLength(32);
builder.Property(x => x.AudioExtension).HasMaxLength(16);
builder
.HasMany(x => x.Variants)
.WithOne()
.HasForeignKey(v => v.BumperTemplateId)
.OnDelete(DeleteBehavior.Cascade);
builder.Navigation(x => x.Variants).UsePropertyAccessMode(PropertyAccessMode.Field);
}
}
public class BumperTextVariantConfiguration : IEntityTypeConfiguration<BumperTextVariant>
{
public void Configure(EntityTypeBuilder<BumperTextVariant> builder)
{
builder.HasIndex(x => new { x.BumperTemplateId, x.Position });
builder.Property(x => x.Name).IsRequired().HasMaxLength(64);
builder.Property(x => x.NowLabel).IsRequired().HasMaxLength(64);
builder.Property(x => x.NextLabel).IsRequired().HasMaxLength(64);
builder.Property(x => x.Line1).IsRequired().HasMaxLength(120);
builder.Property(x => x.Line2).IsRequired().HasMaxLength(120);
builder.Property(x => x.Weight).HasDefaultValue(BumperTextVariant.DefaultWeight);
}
}
@@ -1,53 +1,53 @@
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Settings;
using TeleWave.Domain.Settings;
namespace TeleWave.Infrastructure.Settings;
/// <summary>Настройки сайта поверх key-value таблицы AppSetting. Запись не сохраняет сама —
/// сохранение выполняет UnitOfWorkBehavior команды (используется общий scoped-контекст).</summary>
public sealed class SiteSettings(IAppDbContext dbContext) : ISiteSettings
{
public Task<bool> IsRegistrationEnabledAsync(CancellationToken cancellationToken) =>
dbContext.GetBoolSettingAsync(SettingKeys.RegistrationEnabled, false, cancellationToken);
public async Task SetRegistrationEnabledAsync(bool enabled, CancellationToken cancellationToken)
{
await UpsertAsync(
SettingKeys.RegistrationEnabled,
enabled ? "true" : "false",
cancellationToken
);
}
public Task<string> GetPreferredAudioLanguagesAsync(CancellationToken cancellationToken) =>
dbContext.GetStringSettingAsync(SettingKeys.PreferredAudioLanguages, "", cancellationToken);
public Task SetPreferredAudioLanguagesAsync(
string value,
CancellationToken cancellationToken
) => UpsertAsync(SettingKeys.PreferredAudioLanguages, value, cancellationToken);
public Task<bool> AreChannelNumbersEnabledAsync(CancellationToken cancellationToken) =>
dbContext.GetBoolSettingAsync(SettingKeys.ChannelNumbersEnabled, false, cancellationToken);
public Task SetChannelNumbersEnabledAsync(bool enabled, CancellationToken cancellationToken) =>
UpsertAsync(
SettingKeys.ChannelNumbersEnabled,
enabled ? "true" : "false",
cancellationToken
);
private async Task UpsertAsync(string key, string value, CancellationToken cancellationToken)
{
var existing = await dbContext.AppSettings.FirstOrDefaultAsync(
s => s.Key == key,
cancellationToken
);
if (existing is null)
dbContext.AppSettings.Add(AppSetting.Create(key, value));
else
existing.SetValue(value);
}
}
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Settings;
using TeleWave.Domain.Settings;
namespace TeleWave.Infrastructure.Settings;
/// <summary>Настройки сайта поверх key-value таблицы AppSetting. Запись не сохраняет сама —
/// сохранение выполняет UnitOfWorkBehavior команды (используется общий scoped-контекст).</summary>
public sealed class SiteSettings(IAppDbContext dbContext) : ISiteSettings
{
public Task<bool> IsRegistrationEnabledAsync(CancellationToken cancellationToken) =>
dbContext.GetBoolSettingAsync(SettingKeys.RegistrationEnabled, false, cancellationToken);
public async Task SetRegistrationEnabledAsync(bool enabled, CancellationToken cancellationToken)
{
await UpsertAsync(
SettingKeys.RegistrationEnabled,
enabled ? "true" : "false",
cancellationToken
);
}
public Task<string> GetPreferredAudioLanguagesAsync(CancellationToken cancellationToken) =>
dbContext.GetStringSettingAsync(SettingKeys.PreferredAudioLanguages, "", cancellationToken);
public Task SetPreferredAudioLanguagesAsync(
string value,
CancellationToken cancellationToken
) => UpsertAsync(SettingKeys.PreferredAudioLanguages, value, cancellationToken);
public Task<bool> AreChannelNumbersEnabledAsync(CancellationToken cancellationToken) =>
dbContext.GetBoolSettingAsync(SettingKeys.ChannelNumbersEnabled, false, cancellationToken);
public Task SetChannelNumbersEnabledAsync(bool enabled, CancellationToken cancellationToken) =>
UpsertAsync(
SettingKeys.ChannelNumbersEnabled,
enabled ? "true" : "false",
cancellationToken
);
private async Task UpsertAsync(string key, string value, CancellationToken cancellationToken)
{
var existing = await dbContext.AppSettings.FirstOrDefaultAsync(
s => s.Key == key,
cancellationToken
);
if (existing is null)
dbContext.AppSettings.Add(AppSetting.Create(key, value));
else
existing.SetValue(value);
}
}