Implement PostgresSQL database context

- Add DatabaseType
- Add DatabaseContext
- Add SetupWizardry
- Add DesignTimeDbContextFactory
- Add migration
- Add integration test to travis as separate job (split out others too)
- Other minor code cleanups
This commit is contained in:
Jordan Brown
2020-05-16 07:41:13 -04:00
parent c1ca3cd689
commit d2ab2a885f
15 changed files with 2559 additions and 103 deletions
+50 -5
View File
@@ -41,12 +41,22 @@ jobs:
- DockerBuild=false
- DMAPI=false
- CONFIG=Debug
name: "Test Server Debug"
name: "Debug Unit Tests"
language: csharp
mono: none
dotnet: 3.1
cache:
directories:
- $HOME/.nuget/packages:
- env:
- DoxGeneration=false
- DockerBuild=false
- DMAPI=false
- CONFIG=Release
name: "Release Unit Tests"
language: csharp
mono: none
dotnet: 3.1
services:
- mysql
cache:
directories:
- $HOME/.nuget/packages:
@@ -60,12 +70,47 @@ jobs:
- DockerBuild=false
- DMAPI=false
- CONFIG=Release
name: "Test Server Release"
- TGS4_TEST_DATABASE_TYPE=MySql
- TGS4_TEST_CONNECTION_STRING="server=127.0.0.1;uid=root;pwd=;database=tgs_test"
name: "MySql Integration Test"
language: csharp
mono: none
dotnet: 3.1
cache:
directories:
- $HOME/.nuget/packages:
- env:
- DoxGeneration=false
- DockerBuild=false
- DMAPI=false
- CONFIG=Release
- TGS4_TEST_DATABASE_TYPE=Sqlite
- TGS4_TEST_CONNECTION_STRING="Data Source=TravisTestDB.sqlite3;Mode=ReadWriteCreate"
name: "Sqlite Integration Test"
language: csharp
mono: none
dotnet: 3.1
cache:
directories:
- $HOME/.nuget/packages:
addons:
apt:
packages:
- libc6-i386
- libstdc++6:i386
- env:
- DoxGeneration=false
- DockerBuild=false
- DMAPI=false
- CONFIG=Release
- TGS4_TEST_DATABASE_TYPE=PostgresSql
- TGS4_TEST_CONNECTION_STRING="Application Name=tgstation-server;Host=127.0.0.1;Username=postgres;Password=;Database=TGS_Test"
name: "PostgresSql Integration Test"
language: csharp
mono: none
dotnet: 3.1
services:
- mysql
- postgresql
cache:
directories:
- $HOME/.nuget/packages:
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
set -e
export TGS4_TEST_DISCORD_CHANNEL=493119635319947269
export TGS4_TEST_IRC_CHANNEL=\#botbus
export TGS4_TEST_TEMP_DIRECTORY=~/tgs4_test
#token set in CI settings
$HOME/.dotnet/tools/coverlet bin/$CONFIG/netcoreapp3.1/Tgstation.Server.Tests.dll --target "dotnet" --targetargs "test -c $CONFIG" --format opencover --output "../../TestResults/integration_test.xml" --include "[Tgstation.Server*]*" --exclude "[Tgstation.Server.Tests*]*" --exclude "[Tgstation.Server.Host]Tgstation.Server.Host.Database.Migrations.*"
cd ../../TestResults
bash <(curl -s https://codecov.io/bash) -f integration_test.xml -F integration
+5 -18
View File
@@ -7,6 +7,11 @@ mkdir TestResults
source ~/.nvm/nvm.sh && nvm install 10
if [[ ! -z "${TGS4_TEST_CONNECTION_STRING}" ]]; then
./integration_test.sh
exit
else
cd tests/Tgstation.Server.Api.Tests
dotnet build -c $CONFIG /p:CopyLocalLockFileAssemblies=true
@@ -32,22 +37,6 @@ cd ../Tgstation.Server.Host.Console.Tests
dotnet build -c $CONFIG /p:CopyLocalLockFileAssemblies=true
$HOME/.dotnet/tools/coverlet bin/$CONFIG/netcoreapp3.1/Tgstation.Server.Host.Console.Tests.dll --target "dotnet" --targetargs "test -c $CONFIG --no-build" --format opencover --output "../../TestResults/console.xml" --include "[Tgstation.Server*]*" --exclude "[Tgstation.Server.Host.Console.Tests*]*"
cd ../Tgstation.Server.Tests
export TGS4_TEST_DATABASE_TYPE=MySql
export TGS4_TEST_DISCORD_CHANNEL=493119635319947269
export TGS4_TEST_CONNECTION_STRING="server=127.0.0.1;uid=root;pwd=;database=tgs_test"
export TGS4_TEST_IRC_CHANNEL=\#botbus
export TGS4_TEST_TEMP_DIRECTORY=~/tgs4_test
#token set in CI settings
dotnet build -c $CONFIG /p:CopyLocalLockFileAssemblies=true
$HOME/.dotnet/tools/coverlet bin/$CONFIG/netcoreapp3.1/Tgstation.Server.Tests.dll --target "dotnet" --targetargs "test -c $CONFIG --no-build" --format opencover --output "../../TestResults/servermy.xml" --include "[Tgstation.Server*]*" --exclude "[Tgstation.Server.Tests*]*" --exclude "[Tgstation.Server.Host]Tgstation.Server.Host.Database.Migrations.*"
#Run again for Sqlite
export TGS4_TEST_DATABASE_TYPE=Sqlite
export TGS4_TEST_CONNECTION_STRING="Data Source=TravisTestDB.sqlite3;Mode=ReadWriteCreate"
$HOME/.dotnet/tools/coverlet bin/$CONFIG/netcoreapp3.1/Tgstation.Server.Tests.dll --target "dotnet" --targetargs "test -c $CONFIG --no-build" --format opencover --output "../../TestResults/serversl.xml" --include "[Tgstation.Server*]*" --exclude "[Tgstation.Server.Tests*]*" --exclude "[Tgstation.Server.Host]Tgstation.Server.Host.Database.Migrations.*"
cd ../../TestResults
bash <(curl -s https://codecov.io/bash) -f api.xml -F unittests
@@ -55,5 +44,3 @@ bash <(curl -s https://codecov.io/bash) -f client.xml -F unittests
bash <(curl -s https://codecov.io/bash) -f host.xml -F unittests
bash <(curl -s https://codecov.io/bash) -f watchdog.xml -F unittests
bash <(curl -s https://codecov.io/bash) -f console.xml -F unittests
bash <(curl -s https://codecov.io/bash) -f servermy.xml -F integration
bash <(curl -s https://codecov.io/bash) -f serversl.xml -F integration
@@ -24,5 +24,10 @@
/// Use Sqlite
/// </summary>
Sqlite,
/// <summary>
/// Use PostgresSql
/// </summary>
PostgresSql,
}
}
@@ -117,7 +117,12 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
{
var job = await DatabaseContext.Jobs.Where(x => x.Id == id && x.Instance.Id == Instance.Id).Include(x => x.StartedBy).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var job = await DatabaseContext
.Jobs
.Where(x => x.Id == id && x.Instance.Id == Instance.Id)
.Include(x => x.StartedBy)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (job == default)
return NotFound();
var api = job.ToApi();
@@ -223,6 +223,9 @@ namespace Tgstation.Server.Host.Core
case DatabaseType.Sqlite:
AddTypedContext<SqliteDatabaseContext>();
break;
case DatabaseType.PostgresSql:
AddTypedContext<PostgresSqlDatabaseContext>();
break;
default:
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid {0}: {1}!", nameof(DatabaseType), dbType));
}
@@ -3,6 +3,7 @@ using System.Data.Common;
using System.Data.SqlClient;
using Microsoft.Data.Sqlite;
using MySql.Data.MySqlClient;
using Npgsql;
using Tgstation.Server.Host.Configuration;
namespace Tgstation.Server.Host.Database
@@ -34,6 +35,11 @@ namespace Tgstation.Server.Host.Database
{
ConnectionString = connectionString
};
case DatabaseType.PostgresSql:
return new NpgsqlConnection
{
ConnectionString = connectionString
};
default:
throw new ArgumentOutOfRangeException(nameof(databaseType), databaseType, "Invalid DatabaseType!");
}
@@ -350,9 +350,14 @@ namespace Tgstation.Server.Host.Database
// Update this with new migrations as they are made
string targetMigration = null;
if (DatabaseType == DatabaseType.PostgresSql && version < new Version(4, 3, 0))
throw new NotSupportedException("Cannot migrate below version 4.3.0 with PostgresSql!");
if (version < new Version(4, 1, 0))
throw new NotSupportedException("Cannot migrate below version 4.1.0!");
else if (version < new Version(4, 2, 0))
if (version < new Version(4, 2, 0))
targetMigration = DatabaseType == DatabaseType.Sqlite ? nameof(SLRebuild) : nameof(MSFixCascadingDelete);
if (targetMigration == null)
@@ -375,6 +380,9 @@ namespace Tgstation.Server.Host.Database
case DatabaseType.Sqlite:
migrationSubstitution = "SL{0}";
break;
case DatabaseType.PostgresSql:
migrationSubstitution = "PG{0}";
break;
default:
throw new InvalidOperationException($"Invalid DatabaseType: {DatabaseType}");
}
@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Logging;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.System;
namespace Tgstation.Server.Host.Database.Design
{
/// <inheritdoc />
sealed class PostgresSqlDesignTimeDbContextFactory : IDesignTimeDbContextFactory<PostgresSqlDatabaseContext>
{
/// <inheritdoc />
public PostgresSqlDatabaseContext CreateDbContext(string[] args)
{
using var loggerFactory = new LoggerFactory();
return new PostgresSqlDatabaseContext(
new DbContextOptions<PostgresSqlDatabaseContext>(),
DesignTimeDbContextFactoryHelpers.GetDbContextOptions(
DatabaseType.PostgresSql,
"Application Name=tgstation-server;Host=127.0.0.1;Password=qCkWimNgLfWwpr7TnUHs;Username=postgres;Database=TGS_Design"),
new DatabaseSeeder(
new CryptographySuite(
new PasswordHasher<User>()),
new PlatformIdentifier()),
loggerFactory.CreateLogger<PostgresSqlDatabaseContext>());
}
}
}
@@ -0,0 +1,816 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Tgstation.Server.Host.Database.Migrations
{
[DbContext(typeof(PostgresSqlDatabaseContext))]
[Migration("20200516111712_PGCreate")]
partial class PGCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
.HasAnnotation("ProductVersion", "3.1.4")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ChannelLimit")
.HasColumnType("integer");
b.Property<string>("ConnectionString")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<bool?>("Enabled")
.HasColumnType("boolean");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("character varying(100)")
.HasMaxLength(100);
b.Property<int>("Provider")
.HasColumnType("integer");
b.Property<long>("ReconnectionInterval")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("InstanceId", "Name")
.IsUnique();
b.ToTable("ChatBots");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("ChatSettingsId")
.HasColumnType("bigint");
b.Property<decimal?>("DiscordChannelId")
.HasColumnType("numeric(20,0)");
b.Property<string>("IrcChannel")
.HasColumnType("character varying(100)")
.HasMaxLength(100);
b.Property<bool?>("IsAdminChannel")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("IsUpdatesChannel")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("IsWatchdogChannel")
.IsRequired()
.HasColumnType("boolean");
b.Property<string>("Tag")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.HasKey("Id");
b.HasIndex("ChatSettingsId", "DiscordChannelId")
.IsUnique();
b.HasIndex("ChatSettingsId", "IrcChannel")
.IsUnique();
b.ToTable("ChatChannels");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ByondVersion")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("DMApiMajorVersion")
.HasColumnType("integer");
b.Property<int?>("DMApiMinorVersion")
.HasColumnType("integer");
b.Property<int?>("DMApiPatchVersion")
.HasColumnType("integer");
b.Property<Guid?>("DirectoryName")
.IsRequired()
.HasColumnType("uuid");
b.Property<string>("DmeName")
.IsRequired()
.HasColumnType("text");
b.Property<long>("JobId")
.HasColumnType("bigint");
b.Property<int>("MinimumSecurityLevel")
.HasColumnType("integer");
b.Property<string>("Output")
.IsRequired()
.HasColumnType("text");
b.Property<long>("RevisionInformationId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("DirectoryName");
b.HasIndex("JobId")
.IsUnique();
b.HasIndex("RevisionInformationId");
b.ToTable("CompileJobs");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<bool?>("AllowWebClient")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("AutoStart")
.IsRequired()
.HasColumnType("boolean");
b.Property<long>("HeartbeatSeconds")
.HasColumnType("bigint");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<int>("PrimaryPort")
.HasColumnType("integer");
b.Property<int>("SecondaryPort")
.HasColumnType("integer");
b.Property<int>("SecurityLevel")
.HasColumnType("integer");
b.Property<long>("StartupTimeout")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamDaemonSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiValidationPort")
.HasColumnType("integer");
b.Property<int>("ApiValidationSecurityLevel")
.HasColumnType("integer");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<string>("ProjectName")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamMakerSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DualReattachInformation", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long?>("AlphaId")
.HasColumnType("bigint");
b.Property<bool>("AlphaIsActive")
.HasColumnType("boolean");
b.Property<long?>("BravoId")
.HasColumnType("bigint");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("AlphaId");
b.HasIndex("BravoId");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("WatchdogReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("AutoUpdateInterval")
.HasColumnType("bigint");
b.Property<int>("ChatBotLimit")
.HasColumnType("integer");
b.Property<int>("ConfigurationType")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<bool?>("Online")
.IsRequired()
.HasColumnType("boolean");
b.Property<string>("Path")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Path")
.IsUnique();
b.ToTable("Instances");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<decimal>("ByondRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("ChatBotRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("ConfigurationRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("DreamDaemonRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("DreamMakerRights")
.HasColumnType("numeric(20,0)");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<decimal>("InstanceUserRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("RepositoryRights")
.HasColumnType("numeric(20,0)");
b.Property<long?>("UserId")
.IsRequired()
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("InstanceId");
b.HasIndex("UserId", "InstanceId")
.IsUnique();
b.ToTable("InstanceUsers");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<decimal?>("CancelRight")
.HasColumnType("numeric(20,0)");
b.Property<decimal?>("CancelRightsType")
.HasColumnType("numeric(20,0)");
b.Property<bool?>("Cancelled")
.IsRequired()
.HasColumnType("boolean");
b.Property<long?>("CancelledById")
.HasColumnType("bigint");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<long?>("ErrorCode")
.HasColumnType("bigint");
b.Property<string>("ExceptionDetails")
.HasColumnType("text");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<DateTimeOffset?>("StartedAt")
.IsRequired()
.HasColumnType("timestamp with time zone");
b.Property<long>("StartedById")
.HasColumnType("bigint");
b.Property<DateTimeOffset?>("StoppedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("CancelledById");
b.HasIndex("InstanceId");
b.HasIndex("StartedById");
b.ToTable("Jobs");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("AccessIdentifier")
.IsRequired()
.HasColumnType("text");
b.Property<long>("CompileJobId")
.HasColumnType("bigint");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<int>("LaunchSecurityLevel")
.HasColumnType("integer");
b.Property<int>("Port")
.HasColumnType("integer");
b.Property<int>("ProcessId")
.HasColumnType("integer");
b.Property<int>("RebootState")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("CompileJobId");
b.ToTable("ReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("AccessToken")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<string>("AccessUser")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<bool?>("AutoUpdatesKeepTestMerges")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("AutoUpdatesSynchronize")
.IsRequired()
.HasColumnType("boolean");
b.Property<string>("CommitterEmail")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<string>("CommitterName")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<bool?>("PostTestMergeComment")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("PushTestMergeCommits")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("ShowTestMergeCommitters")
.IsRequired()
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("RepositorySettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("RevisionInformationId")
.HasColumnType("bigint");
b.Property<long>("TestMergeId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("RevisionInformationId");
b.HasIndex("TestMergeId");
b.ToTable("RevInfoTestMerges");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("CommitSha")
.IsRequired()
.HasColumnType("character varying(40)")
.HasMaxLength(40);
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<string>("OriginCommitSha")
.IsRequired()
.HasColumnType("character varying(40)")
.HasMaxLength(40);
b.HasKey("Id");
b.HasIndex("InstanceId", "CommitSha")
.IsUnique();
b.ToTable("RevisionInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Author")
.IsRequired()
.HasColumnType("text");
b.Property<string>("BodyAtMerge")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Comment")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<DateTimeOffset>("MergedAt")
.HasColumnType("timestamp with time zone");
b.Property<long>("MergedById")
.HasColumnType("bigint");
b.Property<int>("Number")
.HasColumnType("integer");
b.Property<long?>("PrimaryRevisionInformationId")
.IsRequired()
.HasColumnType("bigint");
b.Property<string>("PullRequestRevision")
.IsRequired()
.HasColumnType("character varying(40)")
.HasMaxLength(40);
b.Property<string>("TitleAtMerge")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("MergedById");
b.HasIndex("PrimaryRevisionInformationId")
.IsUnique();
b.ToTable("TestMerges");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.Property<long?>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<decimal>("AdministrationRights")
.HasColumnType("numeric(20,0)");
b.Property<string>("CanonicalName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset?>("CreatedAt")
.IsRequired()
.HasColumnType("timestamp with time zone");
b.Property<long?>("CreatedById")
.HasColumnType("bigint");
b.Property<bool?>("Enabled")
.IsRequired()
.HasColumnType("boolean");
b.Property<decimal>("InstanceManagerRights")
.HasColumnType("numeric(20,0)");
b.Property<DateTimeOffset?>("LastPasswordUpdate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("SystemIdentifier")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CanonicalName")
.IsUnique();
b.HasIndex("CreatedById");
b.HasIndex("SystemIdentifier")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("ChatSettings")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings")
.WithMany("Channels")
.HasForeignKey("ChatSettingsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Job", "Job")
.WithOne()
.HasForeignKey("Tgstation.Server.Host.Models.CompileJob", "JobId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("CompileJobs")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.ClientNoAction)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithOne("DreamDaemonSettings")
.HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithOne("DreamMakerSettings")
.HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DualReattachInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.ReattachInformation", "Alpha")
.WithMany()
.HasForeignKey("AlphaId");
b.HasOne("Tgstation.Server.Host.Models.ReattachInformation", "Bravo")
.WithMany()
.HasForeignKey("BravoId");
b.HasOne("Tgstation.Server.Host.Models.Instance", null)
.WithOne("WatchdogReattachInformation")
.HasForeignKey("Tgstation.Server.Host.Models.DualReattachInformation", "InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("InstanceUsers")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.User", null)
.WithMany("InstanceUsers")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "CancelledBy")
.WithMany()
.HasForeignKey("CancelledById");
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("Jobs")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy")
.WithMany()
.HasForeignKey("StartedById")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob")
.WithMany()
.HasForeignKey("CompileJobId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithOne("RepositorySettings")
.HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("ActiveTestMerges")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge")
.WithMany("RevisonInformations")
.HasForeignKey("TestMergeId")
.OnDelete(DeleteBehavior.ClientNoAction)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("RevisionInformations")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy")
.WithMany("TestMerges")
.HasForeignKey("MergedById")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation")
.WithOne("PrimaryTestMerge")
.HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy")
.WithMany("CreatedUsers")
.HasForeignKey("CreatedById");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,638 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <summary>
/// Create initial schema for PostgreSQL.
/// </summary>
public partial class PGCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
if (migrationBuilder == null)
throw new ArgumentNullException(nameof(migrationBuilder));
migrationBuilder.CreateTable(
name: "Instances",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(maxLength: 10000, nullable: false),
Path = table.Column<string>(nullable: false),
Online = table.Column<bool>(nullable: false),
ConfigurationType = table.Column<int>(nullable: false),
AutoUpdateInterval = table.Column<long>(nullable: false),
ChatBotLimit = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Instances", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Enabled = table.Column<bool>(nullable: false),
CreatedAt = table.Column<DateTimeOffset>(nullable: false),
SystemIdentifier = table.Column<string>(nullable: true),
Name = table.Column<string>(maxLength: 10000, nullable: false),
AdministrationRights = table.Column<decimal>(nullable: false),
InstanceManagerRights = table.Column<decimal>(nullable: false),
PasswordHash = table.Column<string>(nullable: true),
CreatedById = table.Column<long>(nullable: true),
CanonicalName = table.Column<string>(nullable: false),
LastPasswordUpdate = table.Column<DateTimeOffset>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
table.ForeignKey(
name: "FK_Users_Users_CreatedById",
column: x => x.CreatedById,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "ChatBots",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(maxLength: 100, nullable: false),
Enabled = table.Column<bool>(nullable: true),
ReconnectionInterval = table.Column<long>(nullable: false),
ChannelLimit = table.Column<int>(nullable: false),
Provider = table.Column<int>(nullable: false),
ConnectionString = table.Column<string>(maxLength: 10000, nullable: false),
InstanceId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ChatBots", x => x.Id);
table.ForeignKey(
name: "FK_ChatBots_Instances_InstanceId",
column: x => x.InstanceId,
principalTable: "Instances",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "DreamDaemonSettings",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AllowWebClient = table.Column<bool>(nullable: false),
SecurityLevel = table.Column<int>(nullable: false),
PrimaryPort = table.Column<int>(nullable: false),
SecondaryPort = table.Column<int>(nullable: false),
StartupTimeout = table.Column<long>(nullable: false),
HeartbeatSeconds = table.Column<long>(nullable: false),
AutoStart = table.Column<bool>(nullable: false),
InstanceId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_DreamDaemonSettings", x => x.Id);
table.ForeignKey(
name: "FK_DreamDaemonSettings_Instances_InstanceId",
column: x => x.InstanceId,
principalTable: "Instances",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "DreamMakerSettings",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ProjectName = table.Column<string>(maxLength: 10000, nullable: true),
ApiValidationPort = table.Column<int>(nullable: false),
ApiValidationSecurityLevel = table.Column<int>(nullable: false),
InstanceId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_DreamMakerSettings", x => x.Id);
table.ForeignKey(
name: "FK_DreamMakerSettings_Instances_InstanceId",
column: x => x.InstanceId,
principalTable: "Instances",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "RepositorySettings",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
CommitterName = table.Column<string>(maxLength: 10000, nullable: false),
CommitterEmail = table.Column<string>(maxLength: 10000, nullable: false),
AccessUser = table.Column<string>(maxLength: 10000, nullable: true),
AccessToken = table.Column<string>(maxLength: 10000, nullable: true),
PushTestMergeCommits = table.Column<bool>(nullable: false),
ShowTestMergeCommitters = table.Column<bool>(nullable: false),
AutoUpdatesKeepTestMerges = table.Column<bool>(nullable: false),
AutoUpdatesSynchronize = table.Column<bool>(nullable: false),
PostTestMergeComment = table.Column<bool>(nullable: false),
InstanceId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RepositorySettings", x => x.Id);
table.ForeignKey(
name: "FK_RepositorySettings_Instances_InstanceId",
column: x => x.InstanceId,
principalTable: "Instances",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "RevisionInformations",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
CommitSha = table.Column<string>(maxLength: 40, nullable: false),
OriginCommitSha = table.Column<string>(maxLength: 40, nullable: false),
InstanceId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RevisionInformations", x => x.Id);
table.ForeignKey(
name: "FK_RevisionInformations_Instances_InstanceId",
column: x => x.InstanceId,
principalTable: "Instances",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "InstanceUsers",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<long>(nullable: false),
InstanceUserRights = table.Column<decimal>(nullable: false),
ByondRights = table.Column<decimal>(nullable: false),
DreamDaemonRights = table.Column<decimal>(nullable: false),
DreamMakerRights = table.Column<decimal>(nullable: false),
RepositoryRights = table.Column<decimal>(nullable: false),
ChatBotRights = table.Column<decimal>(nullable: false),
ConfigurationRights = table.Column<decimal>(nullable: false),
InstanceId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_InstanceUsers", x => x.Id);
table.ForeignKey(
name: "FK_InstanceUsers_Instances_InstanceId",
column: x => x.InstanceId,
principalTable: "Instances",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_InstanceUsers_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Jobs",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Description = table.Column<string>(nullable: false),
ErrorCode = table.Column<long>(nullable: true),
ExceptionDetails = table.Column<string>(nullable: true),
StartedAt = table.Column<DateTimeOffset>(nullable: false),
StoppedAt = table.Column<DateTimeOffset>(nullable: true),
Cancelled = table.Column<bool>(nullable: false),
CancelRightsType = table.Column<decimal>(nullable: true),
CancelRight = table.Column<decimal>(nullable: true),
StartedById = table.Column<long>(nullable: false),
CancelledById = table.Column<long>(nullable: true),
InstanceId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Jobs", x => x.Id);
table.ForeignKey(
name: "FK_Jobs_Users_CancelledById",
column: x => x.CancelledById,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Jobs_Instances_InstanceId",
column: x => x.InstanceId,
principalTable: "Instances",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Jobs_Users_StartedById",
column: x => x.StartedById,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ChatChannels",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
IrcChannel = table.Column<string>(maxLength: 100, nullable: true),
DiscordChannelId = table.Column<decimal>(nullable: true),
IsAdminChannel = table.Column<bool>(nullable: false),
IsWatchdogChannel = table.Column<bool>(nullable: false),
IsUpdatesChannel = table.Column<bool>(nullable: false),
Tag = table.Column<string>(maxLength: 10000, nullable: true),
ChatSettingsId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ChatChannels", x => x.Id);
table.ForeignKey(
name: "FK_ChatChannels_ChatBots_ChatSettingsId",
column: x => x.ChatSettingsId,
principalTable: "ChatBots",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "TestMerges",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Number = table.Column<int>(nullable: false),
PullRequestRevision = table.Column<string>(maxLength: 40, nullable: false),
Comment = table.Column<string>(maxLength: 10000, nullable: true),
TitleAtMerge = table.Column<string>(nullable: false),
BodyAtMerge = table.Column<string>(nullable: false),
Url = table.Column<string>(nullable: false),
Author = table.Column<string>(nullable: false),
MergedAt = table.Column<DateTimeOffset>(nullable: false),
MergedById = table.Column<long>(nullable: false),
PrimaryRevisionInformationId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_TestMerges", x => x.Id);
table.ForeignKey(
name: "FK_TestMerges_Users_MergedById",
column: x => x.MergedById,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_TestMerges_RevisionInformations_PrimaryRevisionInformationId",
column: x => x.PrimaryRevisionInformationId,
principalTable: "RevisionInformations",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "CompileJobs",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
DmeName = table.Column<string>(nullable: false),
Output = table.Column<string>(nullable: false),
DirectoryName = table.Column<Guid>(nullable: false),
MinimumSecurityLevel = table.Column<int>(nullable: false),
JobId = table.Column<long>(nullable: false),
RevisionInformationId = table.Column<long>(nullable: false),
ByondVersion = table.Column<string>(nullable: false),
DMApiMajorVersion = table.Column<int>(nullable: true),
DMApiMinorVersion = table.Column<int>(nullable: true),
DMApiPatchVersion = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CompileJobs", x => x.Id);
table.ForeignKey(
name: "FK_CompileJobs_Jobs_JobId",
column: x => x.JobId,
principalTable: "Jobs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_CompileJobs_RevisionInformations_RevisionInformationId",
column: x => x.RevisionInformationId,
principalTable: "RevisionInformations",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "RevInfoTestMerges",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TestMergeId = table.Column<long>(nullable: false),
RevisionInformationId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RevInfoTestMerges", x => x.Id);
table.ForeignKey(
name: "FK_RevInfoTestMerges_RevisionInformations_RevisionInformationId",
column: x => x.RevisionInformationId,
principalTable: "RevisionInformations",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_RevInfoTestMerges_TestMerges_TestMergeId",
column: x => x.TestMergeId,
principalTable: "TestMerges",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "ReattachInformations",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AccessIdentifier = table.Column<string>(nullable: false),
ProcessId = table.Column<int>(nullable: false),
IsPrimary = table.Column<bool>(nullable: false),
Port = table.Column<int>(nullable: false),
RebootState = table.Column<int>(nullable: false),
LaunchSecurityLevel = table.Column<int>(nullable: false),
CompileJobId = table.Column<long>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ReattachInformations", x => x.Id);
table.ForeignKey(
name: "FK_ReattachInformations_CompileJobs_CompileJobId",
column: x => x.CompileJobId,
principalTable: "CompileJobs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "WatchdogReattachInformations",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AlphaIsActive = table.Column<bool>(nullable: false),
InstanceId = table.Column<long>(nullable: false),
AlphaId = table.Column<long>(nullable: true),
BravoId = table.Column<long>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_WatchdogReattachInformations", x => x.Id);
table.ForeignKey(
name: "FK_WatchdogReattachInformations_ReattachInformations_AlphaId",
column: x => x.AlphaId,
principalTable: "ReattachInformations",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_WatchdogReattachInformations_ReattachInformations_BravoId",
column: x => x.BravoId,
principalTable: "ReattachInformations",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_WatchdogReattachInformations_Instances_InstanceId",
column: x => x.InstanceId,
principalTable: "Instances",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ChatBots_InstanceId_Name",
table: "ChatBots",
columns: new[] { "InstanceId", "Name" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ChatChannels_ChatSettingsId_DiscordChannelId",
table: "ChatChannels",
columns: new[] { "ChatSettingsId", "DiscordChannelId" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ChatChannels_ChatSettingsId_IrcChannel",
table: "ChatChannels",
columns: new[] { "ChatSettingsId", "IrcChannel" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_CompileJobs_DirectoryName",
table: "CompileJobs",
column: "DirectoryName");
migrationBuilder.CreateIndex(
name: "IX_CompileJobs_JobId",
table: "CompileJobs",
column: "JobId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_CompileJobs_RevisionInformationId",
table: "CompileJobs",
column: "RevisionInformationId");
migrationBuilder.CreateIndex(
name: "IX_DreamDaemonSettings_InstanceId",
table: "DreamDaemonSettings",
column: "InstanceId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_DreamMakerSettings_InstanceId",
table: "DreamMakerSettings",
column: "InstanceId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Instances_Path",
table: "Instances",
column: "Path",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_InstanceUsers_InstanceId",
table: "InstanceUsers",
column: "InstanceId");
migrationBuilder.CreateIndex(
name: "IX_InstanceUsers_UserId_InstanceId",
table: "InstanceUsers",
columns: new[] { "UserId", "InstanceId" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Jobs_CancelledById",
table: "Jobs",
column: "CancelledById");
migrationBuilder.CreateIndex(
name: "IX_Jobs_InstanceId",
table: "Jobs",
column: "InstanceId");
migrationBuilder.CreateIndex(
name: "IX_Jobs_StartedById",
table: "Jobs",
column: "StartedById");
migrationBuilder.CreateIndex(
name: "IX_ReattachInformations_CompileJobId",
table: "ReattachInformations",
column: "CompileJobId");
migrationBuilder.CreateIndex(
name: "IX_RepositorySettings_InstanceId",
table: "RepositorySettings",
column: "InstanceId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_RevInfoTestMerges_RevisionInformationId",
table: "RevInfoTestMerges",
column: "RevisionInformationId");
migrationBuilder.CreateIndex(
name: "IX_RevInfoTestMerges_TestMergeId",
table: "RevInfoTestMerges",
column: "TestMergeId");
migrationBuilder.CreateIndex(
name: "IX_RevisionInformations_InstanceId_CommitSha",
table: "RevisionInformations",
columns: new[] { "InstanceId", "CommitSha" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_TestMerges_MergedById",
table: "TestMerges",
column: "MergedById");
migrationBuilder.CreateIndex(
name: "IX_TestMerges_PrimaryRevisionInformationId",
table: "TestMerges",
column: "PrimaryRevisionInformationId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Users_CanonicalName",
table: "Users",
column: "CanonicalName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Users_CreatedById",
table: "Users",
column: "CreatedById");
migrationBuilder.CreateIndex(
name: "IX_Users_SystemIdentifier",
table: "Users",
column: "SystemIdentifier",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_WatchdogReattachInformations_AlphaId",
table: "WatchdogReattachInformations",
column: "AlphaId");
migrationBuilder.CreateIndex(
name: "IX_WatchdogReattachInformations_BravoId",
table: "WatchdogReattachInformations",
column: "BravoId");
migrationBuilder.CreateIndex(
name: "IX_WatchdogReattachInformations_InstanceId",
table: "WatchdogReattachInformations",
column: "InstanceId",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
if (migrationBuilder == null)
throw new ArgumentNullException(nameof(migrationBuilder));
migrationBuilder.DropTable(
name: "ChatChannels");
migrationBuilder.DropTable(
name: "DreamDaemonSettings");
migrationBuilder.DropTable(
name: "DreamMakerSettings");
migrationBuilder.DropTable(
name: "InstanceUsers");
migrationBuilder.DropTable(
name: "RepositorySettings");
migrationBuilder.DropTable(
name: "RevInfoTestMerges");
migrationBuilder.DropTable(
name: "WatchdogReattachInformations");
migrationBuilder.DropTable(
name: "ChatBots");
migrationBuilder.DropTable(
name: "TestMerges");
migrationBuilder.DropTable(
name: "ReattachInformations");
migrationBuilder.DropTable(
name: "CompileJobs");
migrationBuilder.DropTable(
name: "Jobs");
migrationBuilder.DropTable(
name: "RevisionInformations");
migrationBuilder.DropTable(
name: "Users");
migrationBuilder.DropTable(
name: "Instances");
}
}
}
@@ -0,0 +1,815 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Tgstation.Server.Host.Database;
namespace Tgstation.Server.Host.Migrations
{
[DbContext(typeof(PostgresSqlDatabaseContext))]
partial class PostgresSqlDatabaseContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
.HasAnnotation("ProductVersion", "3.1.4")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ChannelLimit")
.HasColumnType("integer");
b.Property<string>("ConnectionString")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<bool?>("Enabled")
.HasColumnType("boolean");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("character varying(100)")
.HasMaxLength(100);
b.Property<int>("Provider")
.HasColumnType("integer");
b.Property<long>("ReconnectionInterval")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("InstanceId", "Name")
.IsUnique();
b.ToTable("ChatBots");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("ChatSettingsId")
.HasColumnType("bigint");
b.Property<decimal?>("DiscordChannelId")
.HasColumnType("numeric(20,0)");
b.Property<string>("IrcChannel")
.HasColumnType("character varying(100)")
.HasMaxLength(100);
b.Property<bool?>("IsAdminChannel")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("IsUpdatesChannel")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("IsWatchdogChannel")
.IsRequired()
.HasColumnType("boolean");
b.Property<string>("Tag")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.HasKey("Id");
b.HasIndex("ChatSettingsId", "DiscordChannelId")
.IsUnique();
b.HasIndex("ChatSettingsId", "IrcChannel")
.IsUnique();
b.ToTable("ChatChannels");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ByondVersion")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("DMApiMajorVersion")
.HasColumnType("integer");
b.Property<int?>("DMApiMinorVersion")
.HasColumnType("integer");
b.Property<int?>("DMApiPatchVersion")
.HasColumnType("integer");
b.Property<Guid?>("DirectoryName")
.IsRequired()
.HasColumnType("uuid");
b.Property<string>("DmeName")
.IsRequired()
.HasColumnType("text");
b.Property<long>("JobId")
.HasColumnType("bigint");
b.Property<int>("MinimumSecurityLevel")
.HasColumnType("integer");
b.Property<string>("Output")
.IsRequired()
.HasColumnType("text");
b.Property<long>("RevisionInformationId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("DirectoryName");
b.HasIndex("JobId")
.IsUnique();
b.HasIndex("RevisionInformationId");
b.ToTable("CompileJobs");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<bool?>("AllowWebClient")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("AutoStart")
.IsRequired()
.HasColumnType("boolean");
b.Property<long>("HeartbeatSeconds")
.HasColumnType("bigint");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<int>("PrimaryPort")
.HasColumnType("integer");
b.Property<int>("SecondaryPort")
.HasColumnType("integer");
b.Property<int>("SecurityLevel")
.HasColumnType("integer");
b.Property<long>("StartupTimeout")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamDaemonSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("ApiValidationPort")
.HasColumnType("integer");
b.Property<int>("ApiValidationSecurityLevel")
.HasColumnType("integer");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<string>("ProjectName")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamMakerSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DualReattachInformation", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long?>("AlphaId")
.HasColumnType("bigint");
b.Property<bool>("AlphaIsActive")
.HasColumnType("boolean");
b.Property<long?>("BravoId")
.HasColumnType("bigint");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("AlphaId");
b.HasIndex("BravoId");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("WatchdogReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("AutoUpdateInterval")
.HasColumnType("bigint");
b.Property<int>("ChatBotLimit")
.HasColumnType("integer");
b.Property<int>("ConfigurationType")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<bool?>("Online")
.IsRequired()
.HasColumnType("boolean");
b.Property<string>("Path")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Path")
.IsUnique();
b.ToTable("Instances");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<decimal>("ByondRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("ChatBotRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("ConfigurationRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("DreamDaemonRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("DreamMakerRights")
.HasColumnType("numeric(20,0)");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<decimal>("InstanceUserRights")
.HasColumnType("numeric(20,0)");
b.Property<decimal>("RepositoryRights")
.HasColumnType("numeric(20,0)");
b.Property<long?>("UserId")
.IsRequired()
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("InstanceId");
b.HasIndex("UserId", "InstanceId")
.IsUnique();
b.ToTable("InstanceUsers");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<decimal?>("CancelRight")
.HasColumnType("numeric(20,0)");
b.Property<decimal?>("CancelRightsType")
.HasColumnType("numeric(20,0)");
b.Property<bool?>("Cancelled")
.IsRequired()
.HasColumnType("boolean");
b.Property<long?>("CancelledById")
.HasColumnType("bigint");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<long?>("ErrorCode")
.HasColumnType("bigint");
b.Property<string>("ExceptionDetails")
.HasColumnType("text");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<DateTimeOffset?>("StartedAt")
.IsRequired()
.HasColumnType("timestamp with time zone");
b.Property<long>("StartedById")
.HasColumnType("bigint");
b.Property<DateTimeOffset?>("StoppedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("CancelledById");
b.HasIndex("InstanceId");
b.HasIndex("StartedById");
b.ToTable("Jobs");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("AccessIdentifier")
.IsRequired()
.HasColumnType("text");
b.Property<long>("CompileJobId")
.HasColumnType("bigint");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<int>("LaunchSecurityLevel")
.HasColumnType("integer");
b.Property<int>("Port")
.HasColumnType("integer");
b.Property<int>("ProcessId")
.HasColumnType("integer");
b.Property<int>("RebootState")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("CompileJobId");
b.ToTable("ReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("AccessToken")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<string>("AccessUser")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<bool?>("AutoUpdatesKeepTestMerges")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("AutoUpdatesSynchronize")
.IsRequired()
.HasColumnType("boolean");
b.Property<string>("CommitterEmail")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<string>("CommitterName")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<bool?>("PostTestMergeComment")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("PushTestMergeCommits")
.IsRequired()
.HasColumnType("boolean");
b.Property<bool?>("ShowTestMergeCommitters")
.IsRequired()
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("RepositorySettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("RevisionInformationId")
.HasColumnType("bigint");
b.Property<long>("TestMergeId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("RevisionInformationId");
b.HasIndex("TestMergeId");
b.ToTable("RevInfoTestMerges");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("CommitSha")
.IsRequired()
.HasColumnType("character varying(40)")
.HasMaxLength(40);
b.Property<long>("InstanceId")
.HasColumnType("bigint");
b.Property<string>("OriginCommitSha")
.IsRequired()
.HasColumnType("character varying(40)")
.HasMaxLength(40);
b.HasKey("Id");
b.HasIndex("InstanceId", "CommitSha")
.IsUnique();
b.ToTable("RevisionInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Author")
.IsRequired()
.HasColumnType("text");
b.Property<string>("BodyAtMerge")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Comment")
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<DateTimeOffset>("MergedAt")
.HasColumnType("timestamp with time zone");
b.Property<long>("MergedById")
.HasColumnType("bigint");
b.Property<int>("Number")
.HasColumnType("integer");
b.Property<long?>("PrimaryRevisionInformationId")
.IsRequired()
.HasColumnType("bigint");
b.Property<string>("PullRequestRevision")
.IsRequired()
.HasColumnType("character varying(40)")
.HasMaxLength(40);
b.Property<string>("TitleAtMerge")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("MergedById");
b.HasIndex("PrimaryRevisionInformationId")
.IsUnique();
b.ToTable("TestMerges");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.Property<long?>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<decimal>("AdministrationRights")
.HasColumnType("numeric(20,0)");
b.Property<string>("CanonicalName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset?>("CreatedAt")
.IsRequired()
.HasColumnType("timestamp with time zone");
b.Property<long?>("CreatedById")
.HasColumnType("bigint");
b.Property<bool?>("Enabled")
.IsRequired()
.HasColumnType("boolean");
b.Property<decimal>("InstanceManagerRights")
.HasColumnType("numeric(20,0)");
b.Property<DateTimeOffset?>("LastPasswordUpdate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("character varying(10000)")
.HasMaxLength(10000);
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("SystemIdentifier")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CanonicalName")
.IsUnique();
b.HasIndex("CreatedById");
b.HasIndex("SystemIdentifier")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("ChatSettings")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings")
.WithMany("Channels")
.HasForeignKey("ChatSettingsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Job", "Job")
.WithOne()
.HasForeignKey("Tgstation.Server.Host.Models.CompileJob", "JobId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("CompileJobs")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.ClientNoAction)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithOne("DreamDaemonSettings")
.HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithOne("DreamMakerSettings")
.HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DualReattachInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.ReattachInformation", "Alpha")
.WithMany()
.HasForeignKey("AlphaId");
b.HasOne("Tgstation.Server.Host.Models.ReattachInformation", "Bravo")
.WithMany()
.HasForeignKey("BravoId");
b.HasOne("Tgstation.Server.Host.Models.Instance", null)
.WithOne("WatchdogReattachInformation")
.HasForeignKey("Tgstation.Server.Host.Models.DualReattachInformation", "InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("InstanceUsers")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.User", null)
.WithMany("InstanceUsers")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "CancelledBy")
.WithMany()
.HasForeignKey("CancelledById");
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("Jobs")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy")
.WithMany()
.HasForeignKey("StartedById")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob")
.WithMany()
.HasForeignKey("CompileJobId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithOne("RepositorySettings")
.HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("ActiveTestMerges")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge")
.WithMany("RevisonInformations")
.HasForeignKey("TestMergeId")
.OnDelete(DeleteBehavior.ClientNoAction)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("RevisionInformations")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy")
.WithMany("TestMerges")
.HasForeignKey("MergedById")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation")
.WithOne("PrimaryTestMerge")
.HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy")
.WithMany("CreatedUsers")
.HasForeignKey("CreatedById");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,43 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using Tgstation.Server.Host.Configuration;
namespace Tgstation.Server.Host.Database
{
/// <summary>
/// <see cref="DatabaseContext{TParentContext}"/> for PostgresSQL.
/// </summary>
sealed class PostgresSqlDatabaseContext : DatabaseContext<PostgresSqlDatabaseContext>
{
/// <summary>
/// Construct a <see cref="SqlServerDatabaseContext"/>
/// </summary>
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TContext}"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
/// <param name="databaseConfiguration">The <see cref="IOptions{TOptions}"/> of <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
/// <param name="databaseSeeder">The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
public PostgresSqlDatabaseContext(
DbContextOptions<PostgresSqlDatabaseContext> dbContextOptions,
IOptions<DatabaseConfiguration> databaseConfiguration,
IDatabaseSeeder databaseSeeder,
ILogger<PostgresSqlDatabaseContext> logger)
: base(dbContextOptions, databaseConfiguration, databaseSeeder, logger)
{ }
/// <inheritdoc />
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
base.OnConfiguring(options);
options.UseNpgsql(DatabaseConfiguration.ConnectionString);
}
/// <inheritdoc />
protected override void ValidateDatabaseType()
{
if (DatabaseType != DatabaseType.PostgresSql)
throw new InvalidOperationException("Invalid DatabaseType for SqliteDatabaseContext!");
}
}
}
+114 -71
View File
@@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Data.Common;
@@ -275,34 +276,38 @@ namespace Tgstation.Server.Host.Setup
/// <summary>
/// Prompt the user for the <see cref="DatabaseType"/>.
/// </summary>
/// <param name="firstTime">If this is the user's first time here.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the input <see cref="DatabaseType"/>.</returns>
async Task<DatabaseType> PromptDatabaseType(CancellationToken cancellationToken)
async Task<DatabaseType> PromptDatabaseType(bool firstTime, CancellationToken cancellationToken)
{
await console.WriteAsync(String.Empty, true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync(
"NOTE: It is HIGHLY reccommended that TGS runs on a complete relational database, specfically *NOT* Sqlite.",
true,
cancellationToken)
.ConfigureAwait(false);
await console.WriteAsync(
"Sqlite, by nature cannot perform several DDL operations. Because of this future compatiblility cannot be guaranteed.",
true,
cancellationToken)
.ConfigureAwait(false);
await console.WriteAsync(
"This means that you may not be able to update to the next minor version of TGS4 without a clean re-installation!",
true,
cancellationToken)
.ConfigureAwait(false);
await console.WriteAsync(
"Please consider taking the time to set up a relational database if this is meant to be a long-standing server.",
true,
cancellationToken)
.ConfigureAwait(false);
await console.WriteAsync(String.Empty, true, cancellationToken).ConfigureAwait(false);
if (firstTime)
{
await console.WriteAsync(String.Empty, true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync(
"NOTE: It is HIGHLY reccommended that TGS runs on a complete relational database, specfically *NOT* Sqlite.",
true,
cancellationToken)
.ConfigureAwait(false);
await console.WriteAsync(
"Sqlite, by nature cannot perform several DDL operations. Because of this future compatiblility cannot be guaranteed.",
true,
cancellationToken)
.ConfigureAwait(false);
await console.WriteAsync(
"This means that you may not be able to update to the next minor version of TGS4 without a clean re-installation!",
true,
cancellationToken)
.ConfigureAwait(false);
await console.WriteAsync(
"Please consider taking the time to set up a relational database if this is meant to be a long-standing server.",
true,
cancellationToken)
.ConfigureAwait(false);
await console.WriteAsync(String.Empty, true, cancellationToken).ConfigureAwait(false);
await asyncDelayer.Delay(TimeSpan.FromSeconds(3), cancellationToken).ConfigureAwait(false);
await asyncDelayer.Delay(TimeSpan.FromSeconds(3), cancellationToken).ConfigureAwait(false);
}
await console.WriteAsync("What SQL database type will you be using?", true, cancellationToken).ConfigureAwait(false);
do
@@ -310,9 +315,10 @@ namespace Tgstation.Server.Host.Setup
await console.WriteAsync(
String.Format(
CultureInfo.InvariantCulture,
"Please enter one of {0}, {1}, {2} or {3}: ",
"Please enter one of {0}, {1}, {2}, {3}, or {4}: ",
DatabaseType.MariaDB,
DatabaseType.MySql,
DatabaseType.PostgresSql,
DatabaseType.SqlServer,
DatabaseType.Sqlite),
false,
@@ -332,19 +338,22 @@ namespace Tgstation.Server.Host.Setup
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the new <see cref="DatabaseConfiguration"/></returns>
#pragma warning disable CA1502 // TODO: Decomplexify
async Task<DatabaseConfiguration> ConfigureDatabase(CancellationToken cancellationToken)
{
bool firstTime = true;
do
{
await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false);
var databaseConfiguration = new DatabaseConfiguration
{
DatabaseType = await PromptDatabaseType(cancellationToken).ConfigureAwait(false)
DatabaseType = await PromptDatabaseType(firstTime, cancellationToken).ConfigureAwait(false)
};
firstTime = false;
string serverAddress = null;
uint? mySQLServerPort = null;
ushort? serverPort = null;
bool isSqliteDB = databaseConfiguration.DatabaseType == DatabaseType.Sqlite;
if (!isSqliteDB)
@@ -353,15 +362,17 @@ namespace Tgstation.Server.Host.Setup
await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync("Enter the server's address and port [<server>:<port> or <server>] (blank for local): ", false, cancellationToken).ConfigureAwait(false);
serverAddress = await console.ReadLineAsync(false, cancellationToken).ConfigureAwait(false);
if (!String.IsNullOrWhiteSpace(serverAddress) && databaseConfiguration.DatabaseType == DatabaseType.SqlServer)
if (String.IsNullOrWhiteSpace(serverAddress))
serverAddress = null;
else if (databaseConfiguration.DatabaseType == DatabaseType.SqlServer)
{
var match = Regex.Match(serverAddress, @"^(?<server>.+):(?<port>.+)$");
if (match.Success)
{
serverAddress = match.Groups["server"].Value;
var portString = match.Groups["port"].Value;
if (uint.TryParse(portString, out uint port))
mySQLServerPort = port;
if (UInt16.TryParse(portString, out var port))
serverPort = port;
else
{
await console.WriteAsync($"Failed to parse port \"{portString}\", please try again.", true, cancellationToken).ConfigureAwait(false);
@@ -434,53 +445,84 @@ namespace Tgstation.Server.Host.Setup
connectionString,
databaseConfiguration.DatabaseType);
if (databaseConfiguration.DatabaseType == DatabaseType.SqlServer)
switch (databaseConfiguration.DatabaseType)
{
var csb = new SqlConnectionStringBuilder
{
ApplicationName = assemblyInformationProvider.VersionPrefix,
DataSource = serverAddress ?? "(local)"
};
case DatabaseType.SqlServer:
{
var csb = new SqlConnectionStringBuilder
{
ApplicationName = assemblyInformationProvider.VersionPrefix,
DataSource = serverAddress ?? "(local)"
};
if (useWinAuth)
csb.IntegratedSecurity = true;
else
{
csb.UserID = username;
csb.Password = password;
}
if (useWinAuth)
csb.IntegratedSecurity = true;
else
{
csb.UserID = username;
csb.Password = password;
}
CreateTestConnection(csb.ConnectionString);
csb.InitialCatalog = databaseName;
databaseConfiguration.ConnectionString = csb.ConnectionString;
}
else if(databaseConfiguration.DatabaseType == DatabaseType.Sqlite)
{
var csb = new SqliteConnectionStringBuilder
{
DataSource = databaseName,
Mode = dbExists ? SqliteOpenMode.ReadOnly : SqliteOpenMode.ReadWriteCreate
};
CreateTestConnection(csb.ConnectionString);
csb.InitialCatalog = databaseName;
databaseConfiguration.ConnectionString = csb.ConnectionString;
}
CreateTestConnection(csb.ConnectionString);
databaseConfiguration.ConnectionString = csb.ConnectionString;
}
else
{
// MySQL/MariaDB
var csb = new MySqlConnectionStringBuilder
{
Server = serverAddress ?? "127.0.0.1",
UserID = username,
Password = password
};
break;
case DatabaseType.MariaDB:
case DatabaseType.MySql:
{
// MySQL/MariaDB
var csb = new MySqlConnectionStringBuilder
{
Server = serverAddress ?? "127.0.0.1",
UserID = username,
Password = password
};
if (mySQLServerPort.HasValue)
csb.Port = mySQLServerPort.Value;
if (serverPort.HasValue)
csb.Port = serverPort.Value;
CreateTestConnection(csb.ConnectionString);
csb.Database = databaseName;
databaseConfiguration.ConnectionString = csb.ConnectionString;
CreateTestConnection(csb.ConnectionString);
csb.Database = databaseName;
databaseConfiguration.ConnectionString = csb.ConnectionString;
}
break;
case DatabaseType.Sqlite:
{
var csb = new SqliteConnectionStringBuilder
{
DataSource = databaseName,
Mode = dbExists ? SqliteOpenMode.ReadOnly : SqliteOpenMode.ReadWriteCreate
};
CreateTestConnection(csb.ConnectionString);
databaseConfiguration.ConnectionString = csb.ConnectionString;
}
break;
case DatabaseType.PostgresSql:
{
var csb = new NpgsqlConnectionStringBuilder
{
ApplicationName = assemblyInformationProvider.VersionPrefix,
Host = serverAddress ?? "127.0.0.1",
Password = password,
Username = username
};
if (serverPort.HasValue)
csb.Port = serverPort.Value;
CreateTestConnection(csb.ConnectionString);
csb.Database = databaseName;
databaseConfiguration.ConnectionString = csb.ConnectionString;
}
break;
default:
throw new InvalidOperationException("Invalid DatabaseType!");
}
try
@@ -502,6 +544,7 @@ namespace Tgstation.Server.Host.Setup
}
while (true);
}
#pragma warning restore CA1502
/// <summary>
/// Prompts the user to create a <see cref="GeneralConfiguration"/>
@@ -48,14 +48,12 @@ namespace Tgstation.Server.Host.Components.Repository.Tests
tempDir,
default);
using (var repo = await TestRepoLoading(tempDir))
{
var gitObject = repo.Lookup("f636418bf47d238d33b0e4a34f0072b23a8aad0e");
Assert.IsNotNull(gitObject);
var commit = gitObject.Peel<Commit>();
using var repo = await TestRepoLoading(tempDir);
var gitObject = repo.Lookup("f636418bf47d238d33b0e4a34f0072b23a8aad0e");
Assert.IsNotNull(gitObject);
var commit = gitObject.Peel<Commit>();
Assert.AreEqual("Update Test.md", commit.Message);
}
Assert.AreEqual("Update Test.md", commit.Message);
}
finally
{