diff --git a/.travis.yml b/.travis.yml
index 38e1a220ac..92868fda01 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -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:
diff --git a/build/integration_test.sh b/build/integration_test.sh
new file mode 100755
index 0000000000..8ae68221fd
--- /dev/null
+++ b/build/integration_test.sh
@@ -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
diff --git a/build/test_core.sh b/build/test_core.sh
index 59577f26b6..c8945bbb02 100755
--- a/build/test_core.sh
+++ b/build/test_core.sh
@@ -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
diff --git a/src/Tgstation.Server.Host/Configuration/DatabaseType.cs b/src/Tgstation.Server.Host/Configuration/DatabaseType.cs
index e370e40c68..78c4c75362 100644
--- a/src/Tgstation.Server.Host/Configuration/DatabaseType.cs
+++ b/src/Tgstation.Server.Host/Configuration/DatabaseType.cs
@@ -24,5 +24,10 @@
/// Use Sqlite
///
Sqlite,
+
+ ///
+ /// Use PostgresSql
+ ///
+ PostgresSql,
}
}
diff --git a/src/Tgstation.Server.Host/Controllers/JobController.cs b/src/Tgstation.Server.Host/Controllers/JobController.cs
index f912483f85..4a3485dfd2 100644
--- a/src/Tgstation.Server.Host/Controllers/JobController.cs
+++ b/src/Tgstation.Server.Host/Controllers/JobController.cs
@@ -117,7 +117,12 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(404)]
public async Task 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();
diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs
index 024602bc58..ca23b3e6f2 100644
--- a/src/Tgstation.Server.Host/Core/Application.cs
+++ b/src/Tgstation.Server.Host/Core/Application.cs
@@ -223,6 +223,9 @@ namespace Tgstation.Server.Host.Core
case DatabaseType.Sqlite:
AddTypedContext();
break;
+ case DatabaseType.PostgresSql:
+ AddTypedContext();
+ break;
default:
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid {0}: {1}!", nameof(DatabaseType), dbType));
}
diff --git a/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs b/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs
index bc0f3f6963..037418fbdc 100644
--- a/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs
+++ b/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs
@@ -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!");
}
diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs
index 0fbf07f722..ea684c161b 100644
--- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs
+++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs
@@ -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}");
}
diff --git a/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs
new file mode 100644
index 0000000000..10963af511
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs
@@ -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
+{
+ ///
+ sealed class PostgresSqlDesignTimeDbContextFactory : IDesignTimeDbContextFactory
+ {
+ ///
+ public PostgresSqlDatabaseContext CreateDbContext(string[] args)
+ {
+ using var loggerFactory = new LoggerFactory();
+ return new PostgresSqlDatabaseContext(
+ new DbContextOptions(),
+ 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()),
+ new PlatformIdentifier()),
+ loggerFactory.CreateLogger());
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.Designer.cs
new file mode 100644
index 0000000000..36d63b62c3
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.Designer.cs
@@ -0,0 +1,816 @@
+//
+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
+ {
+ ///
+ 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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("ChannelLimit")
+ .HasColumnType("integer");
+
+ b.Property("ConnectionString")
+ .IsRequired()
+ .HasColumnType("character varying(10000)")
+ .HasMaxLength(10000);
+
+ b.Property("Enabled")
+ .HasColumnType("boolean");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("character varying(100)")
+ .HasMaxLength(100);
+
+ b.Property("Provider")
+ .HasColumnType("integer");
+
+ b.Property("ReconnectionInterval")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId", "Name")
+ .IsUnique();
+
+ b.ToTable("ChatBots");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("ChatSettingsId")
+ .HasColumnType("bigint");
+
+ b.Property("DiscordChannelId")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("IrcChannel")
+ .HasColumnType("character varying(100)")
+ .HasMaxLength(100);
+
+ b.Property("IsAdminChannel")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("IsUpdatesChannel")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("IsWatchdogChannel")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("ByondVersion")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DMApiMajorVersion")
+ .HasColumnType("integer");
+
+ b.Property("DMApiMinorVersion")
+ .HasColumnType("integer");
+
+ b.Property("DMApiPatchVersion")
+ .HasColumnType("integer");
+
+ b.Property("DirectoryName")
+ .IsRequired()
+ .HasColumnType("uuid");
+
+ b.Property("DmeName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("JobId")
+ .HasColumnType("bigint");
+
+ b.Property("MinimumSecurityLevel")
+ .HasColumnType("integer");
+
+ b.Property("Output")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("AllowWebClient")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("AutoStart")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("HeartbeatSeconds")
+ .HasColumnType("bigint");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("PrimaryPort")
+ .HasColumnType("integer");
+
+ b.Property("SecondaryPort")
+ .HasColumnType("integer");
+
+ b.Property("SecurityLevel")
+ .HasColumnType("integer");
+
+ b.Property("StartupTimeout")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("DreamDaemonSettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("ApiValidationPort")
+ .HasColumnType("integer");
+
+ b.Property("ApiValidationSecurityLevel")
+ .HasColumnType("integer");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("AlphaId")
+ .HasColumnType("bigint");
+
+ b.Property("AlphaIsActive")
+ .HasColumnType("boolean");
+
+ b.Property("BravoId")
+ .HasColumnType("bigint");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("AutoUpdateInterval")
+ .HasColumnType("bigint");
+
+ b.Property("ChatBotLimit")
+ .HasColumnType("integer");
+
+ b.Property("ConfigurationType")
+ .HasColumnType("integer");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("character varying(10000)")
+ .HasMaxLength(10000);
+
+ b.Property("Online")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Path")
+ .IsUnique();
+
+ b.ToTable("Instances");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("ByondRights")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("ChatBotRights")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("ConfigurationRights")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("DreamDaemonRights")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("DreamMakerRights")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("InstanceUserRights")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("RepositoryRights")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("CancelRight")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("CancelRightsType")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("Cancelled")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("CancelledById")
+ .HasColumnType("bigint");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ErrorCode")
+ .HasColumnType("bigint");
+
+ b.Property("ExceptionDetails")
+ .HasColumnType("text");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("StartedAt")
+ .IsRequired()
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("StartedById")
+ .HasColumnType("bigint");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("AccessIdentifier")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CompileJobId")
+ .HasColumnType("bigint");
+
+ b.Property("IsPrimary")
+ .HasColumnType("boolean");
+
+ b.Property("LaunchSecurityLevel")
+ .HasColumnType("integer");
+
+ b.Property("Port")
+ .HasColumnType("integer");
+
+ b.Property("ProcessId")
+ .HasColumnType("integer");
+
+ b.Property("RebootState")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CompileJobId");
+
+ b.ToTable("ReattachInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("AccessToken")
+ .HasColumnType("character varying(10000)")
+ .HasMaxLength(10000);
+
+ b.Property("AccessUser")
+ .HasColumnType("character varying(10000)")
+ .HasMaxLength(10000);
+
+ b.Property("AutoUpdatesKeepTestMerges")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("AutoUpdatesSynchronize")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("CommitterEmail")
+ .IsRequired()
+ .HasColumnType("character varying(10000)")
+ .HasMaxLength(10000);
+
+ b.Property("CommitterName")
+ .IsRequired()
+ .HasColumnType("character varying(10000)")
+ .HasMaxLength(10000);
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("PostTestMergeComment")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("PushTestMergeCommits")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("ShowTestMergeCommitters")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("RepositorySettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("RevisionInformationId")
+ .HasColumnType("bigint");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("CommitSha")
+ .IsRequired()
+ .HasColumnType("character varying(40)")
+ .HasMaxLength(40);
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("Author")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BodyAtMerge")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Comment")
+ .HasColumnType("character varying(10000)")
+ .HasMaxLength(10000);
+
+ b.Property("MergedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("MergedById")
+ .HasColumnType("bigint");
+
+ b.Property("Number")
+ .HasColumnType("integer");
+
+ b.Property("PrimaryRevisionInformationId")
+ .IsRequired()
+ .HasColumnType("bigint");
+
+ b.Property("PullRequestRevision")
+ .IsRequired()
+ .HasColumnType("character varying(40)")
+ .HasMaxLength(40);
+
+ b.Property("TitleAtMerge")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property("AdministrationRights")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("CanonicalName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .IsRequired()
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedById")
+ .HasColumnType("bigint");
+
+ b.Property("Enabled")
+ .IsRequired()
+ .HasColumnType("boolean");
+
+ b.Property("InstanceManagerRights")
+ .HasColumnType("numeric(20,0)");
+
+ b.Property("LastPasswordUpdate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("character varying(10000)")
+ .HasMaxLength(10000);
+
+ b.Property("PasswordHash")
+ .HasColumnType("text");
+
+ b.Property("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
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.cs b/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.cs
new file mode 100644
index 0000000000..af77ee5d60
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Migrations/20200516111712_PGCreate.cs
@@ -0,0 +1,638 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+namespace Tgstation.Server.Host.Database.Migrations
+{
+ ///
+ /// Create initial schema for PostgreSQL.
+ ///
+ public partial class PGCreate : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ if (migrationBuilder == null)
+ throw new ArgumentNullException(nameof(migrationBuilder));
+
+ migrationBuilder.CreateTable(
+ name: "Instances",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ Name = table.Column(maxLength: 10000, nullable: false),
+ Path = table.Column(nullable: false),
+ Online = table.Column(nullable: false),
+ ConfigurationType = table.Column(nullable: false),
+ AutoUpdateInterval = table.Column(nullable: false),
+ ChatBotLimit = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Instances", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Users",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ Enabled = table.Column(nullable: false),
+ CreatedAt = table.Column(nullable: false),
+ SystemIdentifier = table.Column(nullable: true),
+ Name = table.Column(maxLength: 10000, nullable: false),
+ AdministrationRights = table.Column(nullable: false),
+ InstanceManagerRights = table.Column(nullable: false),
+ PasswordHash = table.Column(nullable: true),
+ CreatedById = table.Column(nullable: true),
+ CanonicalName = table.Column(nullable: false),
+ LastPasswordUpdate = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ Name = table.Column(maxLength: 100, nullable: false),
+ Enabled = table.Column(nullable: true),
+ ReconnectionInterval = table.Column(nullable: false),
+ ChannelLimit = table.Column(nullable: false),
+ Provider = table.Column(nullable: false),
+ ConnectionString = table.Column(maxLength: 10000, nullable: false),
+ InstanceId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ AllowWebClient = table.Column(nullable: false),
+ SecurityLevel = table.Column(nullable: false),
+ PrimaryPort = table.Column(nullable: false),
+ SecondaryPort = table.Column(nullable: false),
+ StartupTimeout = table.Column(nullable: false),
+ HeartbeatSeconds = table.Column(nullable: false),
+ AutoStart = table.Column(nullable: false),
+ InstanceId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ ProjectName = table.Column(maxLength: 10000, nullable: true),
+ ApiValidationPort = table.Column(nullable: false),
+ ApiValidationSecurityLevel = table.Column(nullable: false),
+ InstanceId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ CommitterName = table.Column(maxLength: 10000, nullable: false),
+ CommitterEmail = table.Column(maxLength: 10000, nullable: false),
+ AccessUser = table.Column(maxLength: 10000, nullable: true),
+ AccessToken = table.Column(maxLength: 10000, nullable: true),
+ PushTestMergeCommits = table.Column(nullable: false),
+ ShowTestMergeCommitters = table.Column(nullable: false),
+ AutoUpdatesKeepTestMerges = table.Column(nullable: false),
+ AutoUpdatesSynchronize = table.Column(nullable: false),
+ PostTestMergeComment = table.Column(nullable: false),
+ InstanceId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ CommitSha = table.Column(maxLength: 40, nullable: false),
+ OriginCommitSha = table.Column(maxLength: 40, nullable: false),
+ InstanceId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ UserId = table.Column(nullable: false),
+ InstanceUserRights = table.Column(nullable: false),
+ ByondRights = table.Column(nullable: false),
+ DreamDaemonRights = table.Column(nullable: false),
+ DreamMakerRights = table.Column(nullable: false),
+ RepositoryRights = table.Column(nullable: false),
+ ChatBotRights = table.Column(nullable: false),
+ ConfigurationRights = table.Column(nullable: false),
+ InstanceId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ Description = table.Column(nullable: false),
+ ErrorCode = table.Column(nullable: true),
+ ExceptionDetails = table.Column(nullable: true),
+ StartedAt = table.Column(nullable: false),
+ StoppedAt = table.Column(nullable: true),
+ Cancelled = table.Column(nullable: false),
+ CancelRightsType = table.Column(nullable: true),
+ CancelRight = table.Column(nullable: true),
+ StartedById = table.Column(nullable: false),
+ CancelledById = table.Column(nullable: true),
+ InstanceId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ IrcChannel = table.Column(maxLength: 100, nullable: true),
+ DiscordChannelId = table.Column(nullable: true),
+ IsAdminChannel = table.Column(nullable: false),
+ IsWatchdogChannel = table.Column(nullable: false),
+ IsUpdatesChannel = table.Column(nullable: false),
+ Tag = table.Column(maxLength: 10000, nullable: true),
+ ChatSettingsId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ Number = table.Column(nullable: false),
+ PullRequestRevision = table.Column(maxLength: 40, nullable: false),
+ Comment = table.Column(maxLength: 10000, nullable: true),
+ TitleAtMerge = table.Column(nullable: false),
+ BodyAtMerge = table.Column(nullable: false),
+ Url = table.Column(nullable: false),
+ Author = table.Column(nullable: false),
+ MergedAt = table.Column(nullable: false),
+ MergedById = table.Column(nullable: false),
+ PrimaryRevisionInformationId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ DmeName = table.Column(nullable: false),
+ Output = table.Column(nullable: false),
+ DirectoryName = table.Column(nullable: false),
+ MinimumSecurityLevel = table.Column(nullable: false),
+ JobId = table.Column(nullable: false),
+ RevisionInformationId = table.Column(nullable: false),
+ ByondVersion = table.Column(nullable: false),
+ DMApiMajorVersion = table.Column(nullable: true),
+ DMApiMinorVersion = table.Column(nullable: true),
+ DMApiPatchVersion = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ TestMergeId = table.Column(nullable: false),
+ RevisionInformationId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ AccessIdentifier = table.Column(nullable: false),
+ ProcessId = table.Column(nullable: false),
+ IsPrimary = table.Column(nullable: false),
+ Port = table.Column(nullable: false),
+ RebootState = table.Column(nullable: false),
+ LaunchSecurityLevel = table.Column(nullable: false),
+ CompileJobId = table.Column(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(nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ AlphaIsActive = table.Column(nullable: false),
+ InstanceId = table.Column(nullable: false),
+ AlphaId = table.Column(nullable: true),
+ BravoId = table.Column(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);
+ }
+
+ ///
+ 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");
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs
new file mode 100644
index 0000000000..277d665476
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs
@@ -0,0 +1,815 @@
+//
+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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property