Merge pull request #930 from tgstation/921-NoSpam

Add Chat Limits
This commit is contained in:
Jordan Brown
2020-04-20 17:56:42 -04:00
committed by GitHub
24 changed files with 2393 additions and 59 deletions
+2 -2
View File
@@ -3,8 +3,8 @@
<!-- This is the authorative version list -->
<!-- Integration tests will ensure they match across the board -->
<TgsCoreVersion>4.1.0</TgsCoreVersion>
<TgsApiVersion>5.0.1</TgsApiVersion>
<TgsClientVersion>5.0.0</TgsClientVersion>
<TgsApiVersion>5.1.0</TgsApiVersion>
<TgsClientVersion>5.1.0</TgsClientVersion>
<TgsDmapiVersion>5.0.0</TgsDmapiVersion>
<TgsControlPanelVersion>0.1.6</TgsControlPanelVersion>
<TgsHostWatchdogVersion>1.1.0</TgsHostWatchdogVersion>
@@ -289,5 +289,17 @@ namespace Tgstation.Server.Api.Models
/// </summary>
[Description("Missing user ID!")]
UserMissingId,
/// <summary>
/// Attempted to add a <see cref="ChatBot"/> when at or above the <see cref="Instance.ChatBotLimit"/> or it was set to something lower than the existing amount of <see cref="ChatBot"/>.
/// </summary>
[Description("Performing this operation would violate the instance's configured chatBotLimit!")]
ChatBotMax,
/// <summary>
/// Attempted to configure a <see cref="ChatBot"/> with more <see cref="ChatChannel"/>s than the configured limit
/// </summary>
[Description("Set amount of chatChannels exceeds the configured channelLimit!")]
ChatBotMaxChannels,
}
}
@@ -45,6 +45,12 @@ namespace Tgstation.Server.Api.Models
[Required]
public uint? AutoUpdateInterval { get; set; }
/// <summary>
/// The maximum number of <see cref="ChatBot"/>s the <see cref="Instance"/> may contain.
/// </summary>
[Required]
public ushort? ChatBotLimit { get; set; }
/// <summary>
/// The <see cref="Job"/> representing a change of <see cref="Path"/>
/// </summary>
@@ -32,6 +32,12 @@ namespace Tgstation.Server.Api.Models.Internal
[Range(1, UInt32.MaxValue)]
public uint? ReconnectionInterval { get; set; }
/// <summary>
/// The maximum number of <see cref="ChatChannel"/>s the <see cref="ChatBot"/> may contain.
/// </summary>
[Required]
public ushort? ChannelLimit { get; set; }
/// <summary>
/// The <see cref="ChatProvider"/> used for the connection
/// </summary>
@@ -62,5 +62,10 @@ namespace Tgstation.Server.Api.Rights
/// User can change <see cref="Models.Internal.ChatBot.ReconnectionInterval"/>
/// </summary>
WriteReconnectionInterval = 512,
/// <summary>
/// User can change <see cref="Models.Internal.ChatBot.ChannelLimit"/>
/// </summary>
WriteChannelLimit = 1024,
}
}
@@ -56,6 +56,11 @@ namespace Tgstation.Server.Api.Rights
/// <summary>
/// User can change <see cref="Models.Instance.AutoUpdateInterval"/>
/// </summary>
SetAutoUpdate = 256
SetAutoUpdate = 256,
/// <summary>
/// User can change <see cref="Models.Instance.ChatBotLimit"/>.
/// </summary>
SetChatBotLimit = 512
}
}
@@ -5,7 +5,7 @@ using Tgstation.Server.Api.Models;
namespace Tgstation.Server.Client
{
/// <summary>
/// Occurs when the server returns an unknown response
/// Occurs when the server returns a bad request response if the <see cref="ApiException.ErrorCode"/> is present. The server returned an unknown reponse otherwise.
/// </summary>
public sealed class ApiConflictException : ApiException
{
@@ -24,6 +24,7 @@ namespace Tgstation.Server.Host.Controllers
/// <see cref="ApiController"/> for managing <see cref="Api.Models.ChatBot"/>s
/// </summary>
[Route(Routes.Chat)]
#pragma warning disable CA1506 // TODO: Decomplexify
public sealed class ChatController : ApiController
{
/// <summary>
@@ -77,6 +78,15 @@ namespace Tgstation.Server.Host.Controllers
if (earlyOut != null)
return earlyOut;
var countOfExistingBotsInInstance = await DatabaseContext
.ChatBots
.Where(x => x.InstanceId == Instance.Id)
.CountAsync(cancellationToken)
.ConfigureAwait(false);
if (countOfExistingBotsInInstance >= Instance.ChatBotLimit.Value)
return Conflict(new ErrorMessage(ErrorCode.ChatBotMax));
model.Enabled = model.Enabled ?? false;
model.ReconnectionInterval = model.ReconnectionInterval ?? 1;
@@ -89,7 +99,8 @@ namespace Tgstation.Server.Host.Controllers
Channels = model.Channels?.Select(x => ConvertApiChatChannel(x)).ToList() ?? new List<Models.ChatChannel>(), // important that this isn't null
InstanceId = Instance.Id,
Provider = model.Provider,
ReconnectionInterval = model.ReconnectionInterval
ReconnectionInterval = model.ReconnectionInterval,
ChannelLimit = model.ChannelLimit
};
DatabaseContext.ChatBots.Add(dbModel);
@@ -197,8 +208,8 @@ namespace Tgstation.Server.Host.Controllers
[TgsAuthorize(ChatBotRights.WriteChannels | ChatBotRights.WriteConnectionString | ChatBotRights.WriteEnabled | ChatBotRights.WriteName | ChatBotRights.WriteProvider)]
[ProducesResponseType(200)]
[ProducesResponseType(typeof(Api.Models.ChatBot), 200)]
#pragma warning disable CA1502 // TODO: Decomplexify
#pragma warning disable CA1506
#pragma warning disable CA1502 // TODO: Decomplexify
#pragma warning disable CA1506
public async Task<IActionResult> Update([FromBody] Api.Models.ChatBot model, CancellationToken cancellationToken)
#pragma warning restore CA1502
#pragma warning restore CA1506
@@ -217,6 +228,15 @@ namespace Tgstation.Server.Host.Controllers
if (current == default)
return StatusCode((int)HttpStatusCode.Gone);
if ((model.Channels?.Count ?? current.Channels.Count) > (model.ChannelLimit ?? current.ChannelLimit.Value))
{
// 400 or 409 depends on if the client sent both
var errorMessage = new ErrorMessage(ErrorCode.ChatBotMaxChannels);
if (model.Channels != null && model.ChannelLimit.HasValue)
return BadRequest(errorMessage);
return Conflict(errorMessage);
}
var userRights = (ChatBotRights)AuthenticationContext.GetRight(RightsType.ChatBots);
bool anySettingsModified = false;
@@ -304,7 +324,15 @@ namespace Tgstation.Server.Host.Controllers
if (!model.ValidateProviderChannelTypes())
return BadRequest(new ErrorMessage(ErrorCode.ChatBotWrongChannelType));
var defaultMaxChannels = (ulong)Math.Max(Models.ChatBot.DefaultChannelLimit, model.Channels?.Count ?? 0);
if (defaultMaxChannels > UInt16.MaxValue)
return BadRequest(new ErrorMessage(ErrorCode.ChatBotMaxChannels));
if (forCreation)
model.ChannelLimit = model.ChannelLimit ?? (ushort)defaultMaxChannels;
return null;
}
}
#pragma warning restore CA1506
}
@@ -244,6 +244,7 @@ namespace Tgstation.Server.Host.Controllers
Online = false,
Path = model.Path,
AutoUpdateInterval = model.AutoUpdateInterval ?? 0,
ChatBotLimit = model.ChatBotLimit ?? Models.Instance.DefaultChatBotLimit,
RepositorySettings = new RepositorySettings
{
CommitterEmail = "tgstation-server@users.noreply.github.com",
@@ -425,9 +426,22 @@ namespace Tgstation.Server.Host.Controllers
if (CheckModified(x => x.AutoUpdateInterval, InstanceManagerRights.SetAutoUpdate)
|| CheckModified(x => x.ConfigurationType, InstanceManagerRights.SetConfiguration)
|| CheckModified(x => x.Name, InstanceManagerRights.Rename)
|| CheckModified(x => x.Online, InstanceManagerRights.SetOnline))
|| CheckModified(x => x.Online, InstanceManagerRights.SetOnline)
|| CheckModified(x => x.ChatBotLimit, InstanceManagerRights.SetChatBotLimit))
return Forbid();
if (model.ChatBotLimit.HasValue)
{
var countOfExistingChatBots = await DatabaseContext
.ChatBots
.Where(x => x.InstanceId == originalModel.Id)
.CountAsync(cancellationToken)
.ConfigureAwait(false);
if (countOfExistingChatBots > model.ChatBotLimit.Value)
return Conflict(new ErrorMessage(ErrorCode.ChatBotMax));
}
// ensure the current user has write privilege on the instance
var usersInstanceUser = await usersInstanceUserTask.ConfigureAwait(false);
if (usersInstanceUser == default)
@@ -0,0 +1,701 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Tgstation.Server.Host.Database;
namespace Tgstation.Server.Host.Migrations
{
[DbContext(typeof(SqlServerDatabaseContext))]
[Migration("20200420175359_MSLimitsOnChat")]
partial class MSLimitsOnChat
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ChannelLimit");
b.Property<string>("ConnectionString")
.IsRequired()
.HasMaxLength(10000);
b.Property<bool?>("Enabled");
b.Property<long>("InstanceId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100);
b.Property<int>("Provider");
b.Property<long>("ReconnectionInterval");
b.HasKey("Id");
b.HasIndex("InstanceId", "Name")
.IsUnique();
b.ToTable("ChatBots");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<long>("ChatSettingsId");
b.Property<decimal?>("DiscordChannelId")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<string>("IrcChannel")
.HasMaxLength(100);
b.Property<bool?>("IsAdminChannel")
.IsRequired();
b.Property<bool?>("IsUpdatesChannel")
.IsRequired();
b.Property<bool?>("IsWatchdogChannel")
.IsRequired();
b.Property<string>("Tag")
.HasMaxLength(10000);
b.HasKey("Id");
b.HasIndex("ChatSettingsId", "DiscordChannelId")
.IsUnique()
.HasFilter("[DiscordChannelId] IS NOT NULL");
b.HasIndex("ChatSettingsId", "IrcChannel")
.IsUnique()
.HasFilter("[IrcChannel] IS NOT NULL");
b.ToTable("ChatChannels");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ByondVersion")
.IsRequired();
b.Property<Guid?>("DirectoryName")
.IsRequired();
b.Property<string>("DmeName")
.IsRequired();
b.Property<long>("JobId");
b.Property<int>("MinimumSecurityLevel");
b.Property<string>("Output")
.IsRequired();
b.Property<long>("RevisionInformationId");
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()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("AccessToken");
b.Property<bool?>("AllowWebClient")
.IsRequired();
b.Property<bool?>("AutoStart")
.IsRequired();
b.Property<long>("InstanceId");
b.Property<int>("PrimaryPort");
b.Property<int?>("ProcessId");
b.Property<int>("SecondaryPort");
b.Property<int>("SecurityLevel");
b.Property<bool?>("SoftRestart")
.IsRequired();
b.Property<bool?>("SoftShutdown")
.IsRequired();
b.Property<long>("StartupTimeout");
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamDaemonSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ApiValidationPort");
b.Property<int>("ApiValidationSecurityLevel");
b.Property<long>("InstanceId");
b.Property<string>("ProjectName")
.HasMaxLength(10000);
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamMakerSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<long>("AutoUpdateInterval");
b.Property<int>("ChatBotLimit");
b.Property<int>("ConfigurationType");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(10000);
b.Property<bool?>("Online")
.IsRequired();
b.Property<string>("Path")
.IsRequired();
b.HasKey("Id");
b.HasIndex("Path")
.IsUnique();
b.ToTable("Instances");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<decimal>("ByondRights")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<decimal>("ChatBotRights")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<decimal>("ConfigurationRights")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<decimal>("DreamDaemonRights")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<decimal>("DreamMakerRights")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<long>("InstanceId");
b.Property<decimal>("InstanceUserRights")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<decimal>("RepositoryRights")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<long?>("UserId")
.IsRequired();
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()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<decimal?>("CancelRight")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<decimal?>("CancelRightsType")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<bool?>("Cancelled")
.IsRequired();
b.Property<long?>("CancelledById");
b.Property<string>("Description")
.IsRequired();
b.Property<string>("ExceptionDetails");
b.Property<long>("InstanceId");
b.Property<DateTimeOffset?>("StartedAt")
.IsRequired();
b.Property<long?>("StartedById")
.IsRequired();
b.Property<DateTimeOffset?>("StoppedAt");
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()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("AccessIdentifier")
.IsRequired();
b.Property<string>("ChatChannelsJson")
.IsRequired();
b.Property<string>("ChatCommandsJson")
.IsRequired();
b.Property<long>("CompileJobId");
b.Property<bool>("IsPrimary");
b.Property<int>("Port");
b.Property<int>("ProcessId");
b.Property<int>("RebootState");
b.Property<string>("ServerCommandsJson")
.IsRequired();
b.HasKey("Id");
b.HasIndex("CompileJobId");
b.ToTable("ReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("AccessToken")
.HasMaxLength(10000);
b.Property<string>("AccessUser")
.HasMaxLength(10000);
b.Property<bool?>("AutoUpdatesKeepTestMerges")
.IsRequired();
b.Property<bool?>("AutoUpdatesSynchronize")
.IsRequired();
b.Property<string>("CommitterEmail")
.IsRequired()
.HasMaxLength(10000);
b.Property<string>("CommitterName")
.IsRequired()
.HasMaxLength(10000);
b.Property<long>("InstanceId");
b.Property<bool?>("PostTestMergeComment")
.IsRequired();
b.Property<bool?>("PushTestMergeCommits")
.IsRequired();
b.Property<bool?>("ShowTestMergeCommitters")
.IsRequired();
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("RepositorySettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<long>("RevisionInformationId");
b.Property<long>("TestMergeId");
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()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("CommitSha")
.IsRequired()
.HasMaxLength(40);
b.Property<long>("InstanceId");
b.Property<string>("OriginCommitSha")
.IsRequired()
.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()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("Author")
.IsRequired();
b.Property<string>("BodyAtMerge")
.IsRequired();
b.Property<string>("Comment")
.HasMaxLength(10000);
b.Property<DateTimeOffset>("MergedAt");
b.Property<long?>("MergedById")
.IsRequired();
b.Property<int>("Number");
b.Property<long?>("PrimaryRevisionInformationId")
.IsRequired();
b.Property<string>("PullRequestRevision")
.IsRequired()
.HasMaxLength(40);
b.Property<string>("TitleAtMerge")
.IsRequired();
b.Property<string>("Url")
.IsRequired();
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()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<decimal>("AdministrationRights")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<string>("CanonicalName")
.IsRequired();
b.Property<DateTimeOffset?>("CreatedAt")
.IsRequired();
b.Property<long?>("CreatedById");
b.Property<bool?>("Enabled")
.IsRequired();
b.Property<decimal>("InstanceManagerRights")
.HasConversion(new ValueConverter<decimal, decimal>(v => default(decimal), v => default(decimal), new ConverterMappingHints(precision: 20, scale: 0)));
b.Property<DateTimeOffset?>("LastPasswordUpdate");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(10000);
b.Property<string>("PasswordHash");
b.Property<string>("SystemIdentifier");
b.HasKey("Id");
b.HasIndex("CanonicalName")
.IsUnique();
b.HasIndex("CreatedById");
b.HasIndex("SystemIdentifier")
.IsUnique()
.HasFilter("[SystemIdentifier] IS NOT NULL");
b.ToTable("Users");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.WatchdogReattachInformation", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<long?>("AlphaId");
b.Property<bool>("AlphaIsActive");
b.Property<long?>("BravoId");
b.Property<long>("InstanceId");
b.HasKey("Id");
b.HasIndex("AlphaId");
b.HasIndex("BravoId");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("WatchdogReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("ChatSettings")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings")
.WithMany("Channels")
.HasForeignKey("ChatSettingsId")
.OnDelete(DeleteBehavior.Cascade);
});
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.Restrict);
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("CompileJobs")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.Cascade);
});
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);
});
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);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("InstanceUsers")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Tgstation.Server.Host.Models.User")
.WithMany("InstanceUsers")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
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);
b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy")
.WithMany()
.HasForeignKey("StartedById")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob")
.WithMany()
.HasForeignKey("CompileJobId")
.OnDelete(DeleteBehavior.Cascade);
});
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);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("ActiveTestMerges")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge")
.WithMany("RevisonInformations")
.HasForeignKey("TestMergeId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("RevisionInformations")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy")
.WithMany("TestMerges")
.HasForeignKey("MergedById")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation")
.WithOne("PrimaryTestMerge")
.HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId")
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy")
.WithMany("CreatedUsers")
.HasForeignKey("CreatedById");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.WatchdogReattachInformation", 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")
.WithOne("WatchdogReattachInformation")
.HasForeignKey("Tgstation.Server.Host.Models.WatchdogReattachInformation", "InstanceId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,46 @@
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using Tgstation.Server.Host.Models;
namespace Tgstation.Server.Host.Migrations
{
/// <summary>
/// Adds chat limits for MSSQL.
/// </summary>
public partial class MSLimitsOnChat : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
if (migrationBuilder == null)
throw new ArgumentNullException(nameof(migrationBuilder));
migrationBuilder.AddColumn<int>(
name: "ChatBotLimit",
table: "Instances",
nullable: false,
defaultValue: Instance.DefaultChatBotLimit);
migrationBuilder.AddColumn<int>(
name: "ChannelLimit",
table: "ChatBots",
nullable: false,
defaultValue: ChatBot.DefaultChannelLimit);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
if (migrationBuilder == null)
throw new ArgumentNullException(nameof(migrationBuilder));
migrationBuilder.DropColumn(
name: "ChatBotLimit",
table: "Instances");
migrationBuilder.DropColumn(
name: "ChannelLimit",
table: "ChatBots");
}
}
}
@@ -0,0 +1,676 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Tgstation.Server.Host.Database;
namespace Tgstation.Server.Host.Migrations
{
[DbContext(typeof(MySqlDatabaseContext))]
[Migration("20200420181015_MYLimitsOnChat")]
partial class MYLimitsOnChat
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<ushort?>("ChannelLimit")
.IsRequired();
b.Property<string>("ConnectionString")
.IsRequired()
.HasMaxLength(10000);
b.Property<bool?>("Enabled");
b.Property<long>("InstanceId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100);
b.Property<int>("Provider");
b.Property<uint?>("ReconnectionInterval")
.IsRequired();
b.HasKey("Id");
b.HasIndex("InstanceId", "Name")
.IsUnique();
b.ToTable("ChatBots");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("ChatSettingsId");
b.Property<ulong?>("DiscordChannelId");
b.Property<string>("IrcChannel")
.HasMaxLength(100);
b.Property<bool?>("IsAdminChannel")
.IsRequired();
b.Property<bool?>("IsUpdatesChannel")
.IsRequired();
b.Property<bool?>("IsWatchdogChannel")
.IsRequired();
b.Property<string>("Tag")
.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();
b.Property<string>("ByondVersion")
.IsRequired();
b.Property<Guid?>("DirectoryName")
.IsRequired();
b.Property<string>("DmeName")
.IsRequired();
b.Property<long>("JobId");
b.Property<int>("MinimumSecurityLevel");
b.Property<string>("Output")
.IsRequired();
b.Property<long>("RevisionInformationId");
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();
b.Property<string>("AccessToken");
b.Property<bool?>("AllowWebClient")
.IsRequired();
b.Property<bool?>("AutoStart")
.IsRequired();
b.Property<long>("InstanceId");
b.Property<ushort?>("PrimaryPort")
.IsRequired();
b.Property<int?>("ProcessId");
b.Property<ushort?>("SecondaryPort")
.IsRequired();
b.Property<int>("SecurityLevel");
b.Property<bool?>("SoftRestart")
.IsRequired();
b.Property<bool?>("SoftShutdown")
.IsRequired();
b.Property<uint?>("StartupTimeout")
.IsRequired();
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamDaemonSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<ushort?>("ApiValidationPort")
.IsRequired();
b.Property<int>("ApiValidationSecurityLevel");
b.Property<long>("InstanceId");
b.Property<string>("ProjectName")
.HasMaxLength(10000);
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamMakerSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<uint?>("AutoUpdateInterval")
.IsRequired();
b.Property<ushort?>("ChatBotLimit")
.IsRequired();
b.Property<int>("ConfigurationType");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(10000);
b.Property<bool?>("Online")
.IsRequired();
b.Property<string>("Path")
.IsRequired();
b.HasKey("Id");
b.HasIndex("Path")
.IsUnique();
b.ToTable("Instances");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ByondRights");
b.Property<ulong>("ChatBotRights");
b.Property<ulong>("ConfigurationRights");
b.Property<ulong>("DreamDaemonRights");
b.Property<ulong>("DreamMakerRights");
b.Property<long>("InstanceId");
b.Property<ulong>("InstanceUserRights");
b.Property<ulong>("RepositoryRights");
b.Property<long?>("UserId")
.IsRequired();
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();
b.Property<ulong?>("CancelRight");
b.Property<ulong?>("CancelRightsType");
b.Property<bool?>("Cancelled")
.IsRequired();
b.Property<long?>("CancelledById");
b.Property<string>("Description")
.IsRequired();
b.Property<string>("ExceptionDetails");
b.Property<long>("InstanceId");
b.Property<DateTimeOffset?>("StartedAt")
.IsRequired();
b.Property<long?>("StartedById")
.IsRequired();
b.Property<DateTimeOffset?>("StoppedAt");
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();
b.Property<string>("AccessIdentifier")
.IsRequired();
b.Property<string>("ChatChannelsJson")
.IsRequired();
b.Property<string>("ChatCommandsJson")
.IsRequired();
b.Property<long>("CompileJobId");
b.Property<bool>("IsPrimary");
b.Property<ushort>("Port");
b.Property<int>("ProcessId");
b.Property<int>("RebootState");
b.Property<string>("ServerCommandsJson")
.IsRequired();
b.HasKey("Id");
b.HasIndex("CompileJobId");
b.ToTable("ReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("AccessToken")
.HasMaxLength(10000);
b.Property<string>("AccessUser")
.HasMaxLength(10000);
b.Property<bool?>("AutoUpdatesKeepTestMerges")
.IsRequired();
b.Property<bool?>("AutoUpdatesSynchronize")
.IsRequired();
b.Property<string>("CommitterEmail")
.IsRequired()
.HasMaxLength(10000);
b.Property<string>("CommitterName")
.IsRequired()
.HasMaxLength(10000);
b.Property<long>("InstanceId");
b.Property<bool?>("PostTestMergeComment")
.IsRequired();
b.Property<bool?>("PushTestMergeCommits")
.IsRequired();
b.Property<bool?>("ShowTestMergeCommitters")
.IsRequired();
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("RepositorySettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("RevisionInformationId");
b.Property<long>("TestMergeId");
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();
b.Property<string>("CommitSha")
.IsRequired()
.HasMaxLength(40);
b.Property<long>("InstanceId");
b.Property<string>("OriginCommitSha")
.IsRequired()
.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();
b.Property<string>("Author")
.IsRequired();
b.Property<string>("BodyAtMerge")
.IsRequired();
b.Property<string>("Comment")
.HasMaxLength(10000);
b.Property<DateTimeOffset>("MergedAt");
b.Property<long?>("MergedById")
.IsRequired();
b.Property<int>("Number");
b.Property<long?>("PrimaryRevisionInformationId")
.IsRequired();
b.Property<string>("PullRequestRevision")
.IsRequired()
.HasMaxLength(40);
b.Property<string>("TitleAtMerge")
.IsRequired();
b.Property<string>("Url")
.IsRequired();
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();
b.Property<ulong>("AdministrationRights");
b.Property<string>("CanonicalName")
.IsRequired();
b.Property<DateTimeOffset?>("CreatedAt")
.IsRequired();
b.Property<long?>("CreatedById");
b.Property<bool?>("Enabled")
.IsRequired();
b.Property<ulong>("InstanceManagerRights");
b.Property<DateTimeOffset?>("LastPasswordUpdate");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(10000);
b.Property<string>("PasswordHash");
b.Property<string>("SystemIdentifier");
b.HasKey("Id");
b.HasIndex("CanonicalName")
.IsUnique();
b.HasIndex("CreatedById");
b.HasIndex("SystemIdentifier")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.WatchdogReattachInformation", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<long?>("AlphaId");
b.Property<bool>("AlphaIsActive");
b.Property<long?>("BravoId");
b.Property<long>("InstanceId");
b.HasKey("Id");
b.HasIndex("AlphaId");
b.HasIndex("BravoId");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("WatchdogReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("ChatSettings")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings")
.WithMany("Channels")
.HasForeignKey("ChatSettingsId")
.OnDelete(DeleteBehavior.Cascade);
});
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.Restrict);
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("CompileJobs")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.Cascade);
});
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);
});
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);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("InstanceUsers")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Tgstation.Server.Host.Models.User")
.WithMany("InstanceUsers")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
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);
b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy")
.WithMany()
.HasForeignKey("StartedById")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob")
.WithMany()
.HasForeignKey("CompileJobId")
.OnDelete(DeleteBehavior.Cascade);
});
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);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("ActiveTestMerges")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge")
.WithMany("RevisonInformations")
.HasForeignKey("TestMergeId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("RevisionInformations")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy")
.WithMany("TestMerges")
.HasForeignKey("MergedById")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation")
.WithOne("PrimaryTestMerge")
.HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId")
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy")
.WithMany("CreatedUsers")
.HasForeignKey("CreatedById");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.WatchdogReattachInformation", 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")
.WithOne("WatchdogReattachInformation")
.HasForeignKey("Tgstation.Server.Host.Models.WatchdogReattachInformation", "InstanceId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,46 @@
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using Tgstation.Server.Host.Models;
namespace Tgstation.Server.Host.Migrations
{
/// <summary>
/// Adds chat limits for MYSQL.
/// </summary>
public partial class MYLimitsOnChat : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
if (migrationBuilder == null)
throw new ArgumentNullException(nameof(migrationBuilder));
migrationBuilder.AddColumn<ushort>(
name: "ChatBotLimit",
table: "Instances",
nullable: false,
defaultValue: Instance.DefaultChatBotLimit);
migrationBuilder.AddColumn<ushort>(
name: "ChannelLimit",
table: "ChatBots",
nullable: false,
defaultValue: ChatBot.DefaultChannelLimit);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
if (migrationBuilder == null)
throw new ArgumentNullException(nameof(migrationBuilder));
migrationBuilder.DropColumn(
name: "ChatBotLimit",
table: "Instances");
migrationBuilder.DropColumn(
name: "ChannelLimit",
table: "ChatBots");
}
}
}
@@ -0,0 +1,675 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Tgstation.Server.Host.Database;
namespace Tgstation.Server.Host.Migrations
{
[DbContext(typeof(SqliteDatabaseContext))]
[Migration("20200420181612_SLLimitsOnChat")]
partial class SLLimitsOnChat
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079");
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<ushort?>("ChannelLimit")
.IsRequired();
b.Property<string>("ConnectionString")
.IsRequired()
.HasMaxLength(10000);
b.Property<bool?>("Enabled");
b.Property<long>("InstanceId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100);
b.Property<int>("Provider");
b.Property<uint?>("ReconnectionInterval")
.IsRequired();
b.HasKey("Id");
b.HasIndex("InstanceId", "Name")
.IsUnique();
b.ToTable("ChatBots");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("ChatSettingsId");
b.Property<ulong?>("DiscordChannelId");
b.Property<string>("IrcChannel")
.HasMaxLength(100);
b.Property<bool?>("IsAdminChannel")
.IsRequired();
b.Property<bool?>("IsUpdatesChannel")
.IsRequired();
b.Property<bool?>("IsWatchdogChannel")
.IsRequired();
b.Property<string>("Tag")
.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();
b.Property<string>("ByondVersion")
.IsRequired();
b.Property<Guid?>("DirectoryName")
.IsRequired();
b.Property<string>("DmeName")
.IsRequired();
b.Property<long>("JobId");
b.Property<int>("MinimumSecurityLevel");
b.Property<string>("Output")
.IsRequired();
b.Property<long>("RevisionInformationId");
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();
b.Property<string>("AccessToken");
b.Property<bool?>("AllowWebClient")
.IsRequired();
b.Property<bool?>("AutoStart")
.IsRequired();
b.Property<long>("InstanceId");
b.Property<ushort?>("PrimaryPort")
.IsRequired();
b.Property<int?>("ProcessId");
b.Property<ushort?>("SecondaryPort")
.IsRequired();
b.Property<int>("SecurityLevel");
b.Property<bool?>("SoftRestart")
.IsRequired();
b.Property<bool?>("SoftShutdown")
.IsRequired();
b.Property<uint?>("StartupTimeout")
.IsRequired();
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamDaemonSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<ushort?>("ApiValidationPort")
.IsRequired();
b.Property<int>("ApiValidationSecurityLevel");
b.Property<long>("InstanceId");
b.Property<string>("ProjectName")
.HasMaxLength(10000);
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DreamMakerSettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<uint?>("AutoUpdateInterval")
.IsRequired();
b.Property<ushort?>("ChatBotLimit")
.IsRequired();
b.Property<int>("ConfigurationType");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(10000);
b.Property<bool?>("Online")
.IsRequired();
b.Property<string>("Path")
.IsRequired();
b.HasKey("Id");
b.HasIndex("Path")
.IsUnique();
b.ToTable("Instances");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ByondRights");
b.Property<ulong>("ChatBotRights");
b.Property<ulong>("ConfigurationRights");
b.Property<ulong>("DreamDaemonRights");
b.Property<ulong>("DreamMakerRights");
b.Property<long>("InstanceId");
b.Property<ulong>("InstanceUserRights");
b.Property<ulong>("RepositoryRights");
b.Property<long?>("UserId")
.IsRequired();
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();
b.Property<ulong?>("CancelRight");
b.Property<ulong?>("CancelRightsType");
b.Property<bool?>("Cancelled")
.IsRequired();
b.Property<long?>("CancelledById");
b.Property<string>("Description")
.IsRequired();
b.Property<string>("ExceptionDetails");
b.Property<long>("InstanceId");
b.Property<DateTimeOffset?>("StartedAt")
.IsRequired();
b.Property<long?>("StartedById")
.IsRequired();
b.Property<DateTimeOffset?>("StoppedAt");
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();
b.Property<string>("AccessIdentifier")
.IsRequired();
b.Property<string>("ChatChannelsJson")
.IsRequired();
b.Property<string>("ChatCommandsJson")
.IsRequired();
b.Property<long>("CompileJobId");
b.Property<bool>("IsPrimary");
b.Property<ushort>("Port");
b.Property<int>("ProcessId");
b.Property<int>("RebootState");
b.Property<string>("ServerCommandsJson")
.IsRequired();
b.HasKey("Id");
b.HasIndex("CompileJobId");
b.ToTable("ReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("AccessToken")
.HasMaxLength(10000);
b.Property<string>("AccessUser")
.HasMaxLength(10000);
b.Property<bool?>("AutoUpdatesKeepTestMerges")
.IsRequired();
b.Property<bool?>("AutoUpdatesSynchronize")
.IsRequired();
b.Property<string>("CommitterEmail")
.IsRequired()
.HasMaxLength(10000);
b.Property<string>("CommitterName")
.IsRequired()
.HasMaxLength(10000);
b.Property<long>("InstanceId");
b.Property<bool?>("PostTestMergeComment")
.IsRequired();
b.Property<bool?>("PushTestMergeCommits")
.IsRequired();
b.Property<bool?>("ShowTestMergeCommitters")
.IsRequired();
b.HasKey("Id");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("RepositorySettings");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("RevisionInformationId");
b.Property<long>("TestMergeId");
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();
b.Property<string>("CommitSha")
.IsRequired()
.HasMaxLength(40);
b.Property<long>("InstanceId");
b.Property<string>("OriginCommitSha")
.IsRequired()
.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();
b.Property<string>("Author")
.IsRequired();
b.Property<string>("BodyAtMerge")
.IsRequired();
b.Property<string>("Comment")
.HasMaxLength(10000);
b.Property<DateTimeOffset>("MergedAt");
b.Property<long?>("MergedById")
.IsRequired();
b.Property<int>("Number");
b.Property<long?>("PrimaryRevisionInformationId")
.IsRequired();
b.Property<string>("PullRequestRevision")
.IsRequired()
.HasMaxLength(40);
b.Property<string>("TitleAtMerge")
.IsRequired();
b.Property<string>("Url")
.IsRequired();
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();
b.Property<ulong>("AdministrationRights");
b.Property<string>("CanonicalName")
.IsRequired();
b.Property<DateTimeOffset?>("CreatedAt")
.IsRequired();
b.Property<long?>("CreatedById");
b.Property<bool?>("Enabled")
.IsRequired();
b.Property<ulong>("InstanceManagerRights");
b.Property<DateTimeOffset?>("LastPasswordUpdate");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(10000);
b.Property<string>("PasswordHash");
b.Property<string>("SystemIdentifier");
b.HasKey("Id");
b.HasIndex("CanonicalName")
.IsUnique();
b.HasIndex("CreatedById");
b.HasIndex("SystemIdentifier")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.WatchdogReattachInformation", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<long?>("AlphaId");
b.Property<bool>("AlphaIsActive");
b.Property<long?>("BravoId");
b.Property<long>("InstanceId");
b.HasKey("Id");
b.HasIndex("AlphaId");
b.HasIndex("BravoId");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("WatchdogReattachInformations");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("ChatSettings")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
{
b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings")
.WithMany("Channels")
.HasForeignKey("ChatSettingsId")
.OnDelete(DeleteBehavior.Cascade);
});
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.Restrict);
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("CompileJobs")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.Cascade);
});
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);
});
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);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.InstanceUser", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("InstanceUsers")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Tgstation.Server.Host.Models.User")
.WithMany("InstanceUsers")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
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);
b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy")
.WithMany()
.HasForeignKey("StartedById")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob")
.WithMany()
.HasForeignKey("CompileJobId")
.OnDelete(DeleteBehavior.Cascade);
});
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);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
.WithMany("ActiveTestMerges")
.HasForeignKey("RevisionInformationId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge")
.WithMany("RevisonInformations")
.HasForeignKey("TestMergeId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
{
b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
.WithMany("RevisionInformations")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy")
.WithMany("TestMerges")
.HasForeignKey("MergedById")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation")
.WithOne("PrimaryTestMerge")
.HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId")
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy")
.WithMany("CreatedUsers")
.HasForeignKey("CreatedById");
});
modelBuilder.Entity("Tgstation.Server.Host.Models.WatchdogReattachInformation", 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")
.WithOne("WatchdogReattachInformation")
.HasForeignKey("Tgstation.Server.Host.Models.WatchdogReattachInformation", "InstanceId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,46 @@
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using Tgstation.Server.Host.Models;
namespace Tgstation.Server.Host.Migrations
{
/// <summary>
/// Adds chat limits for SQLite.
/// </summary>
public partial class SLLimitsOnChat : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
if (migrationBuilder == null)
throw new ArgumentNullException(nameof(migrationBuilder));
migrationBuilder.AddColumn<ushort>(
name: "ChatBotLimit",
table: "Instances",
nullable: false,
defaultValue: Instance.DefaultChatBotLimit);
migrationBuilder.AddColumn<ushort>(
name: "ChannelLimit",
table: "ChatBots",
nullable: false,
defaultValue: ChatBot.DefaultChannelLimit);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
if (migrationBuilder == null)
throw new ArgumentNullException(nameof(migrationBuilder));
migrationBuilder.DropColumn(
name: "ChatBotLimit",
table: "Instances");
migrationBuilder.DropColumn(
name: "ChannelLimit",
table: "ChatBots");
}
}
}
@@ -5,13 +5,9 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <summary>
/// Model snapshot for MYSQL.
/// </summary>
[DbContext(typeof(MySqlDatabaseContext))]
partial class MySqlDatabaseContextModelSnapshot : ModelSnapshot
{
/// <inheritdoc />
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
@@ -24,6 +20,9 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<ushort?>("ChannelLimit")
.IsRequired();
b.Property<string>("ConnectionString")
.IsRequired()
.HasMaxLength(10000);
@@ -192,6 +191,9 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<uint?>("AutoUpdateInterval")
.IsRequired();
b.Property<ushort?>("ChatBotLimit")
.IsRequired();
b.Property<int>("ConfigurationType");
b.Property<string>("Name")
@@ -270,7 +272,8 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<DateTimeOffset?>("StartedAt")
.IsRequired();
b.Property<long>("StartedById");
b.Property<long?>("StartedById")
.IsRequired();
b.Property<DateTimeOffset?>("StoppedAt");
@@ -420,11 +423,11 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<DateTimeOffset>("MergedAt");
b.Property<long>("MergedById");
b.Property<int?>("Number")
b.Property<long?>("MergedById")
.IsRequired();
b.Property<int>("Number");
b.Property<long?>("PrimaryRevisionInformationId")
.IsRequired();
@@ -450,7 +453,7 @@ namespace Tgstation.Server.Host.Database.Migrations
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.Property<long>("Id")
b.Property<long?>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AdministrationRights");
@@ -7,13 +7,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <summary>
/// Model snapshot for MYSQL.
/// </summary>
[DbContext(typeof(SqlServerDatabaseContext))]
partial class SqlServerDatabaseContextModelSnapshot : ModelSnapshot
{
/// <inheritdoc />
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
@@ -28,6 +24,8 @@ namespace Tgstation.Server.Host.Database.Migrations
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("ChannelLimit");
b.Property<string>("ConnectionString")
.IsRequired()
.HasMaxLength(10000);
@@ -198,6 +196,8 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<long>("AutoUpdateInterval");
b.Property<int>("ChatBotLimit");
b.Property<int>("ConfigurationType");
b.Property<string>("Name")
@@ -287,7 +287,8 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<DateTimeOffset?>("StartedAt")
.IsRequired();
b.Property<long>("StartedById");
b.Property<long?>("StartedById")
.IsRequired();
b.Property<DateTimeOffset?>("StoppedAt");
@@ -442,11 +443,11 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<DateTimeOffset>("MergedAt");
b.Property<long>("MergedById");
b.Property<int?>("Number")
b.Property<long?>("MergedById")
.IsRequired();
b.Property<int>("Number");
b.Property<long?>("PrimaryRevisionInformationId")
.IsRequired();
@@ -472,7 +473,7 @@ namespace Tgstation.Server.Host.Database.Migrations
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.Property<long>("Id")
b.Property<long?>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
@@ -5,13 +5,9 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <summary>
/// Model snapshot for SQLite.
/// </summary>
[DbContext(typeof(SqliteDatabaseContext))]
partial class SqliteDatabaseContextModelSnapshot : ModelSnapshot
{
/// <inheritdoc />
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
@@ -23,6 +19,9 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<ushort?>("ChannelLimit")
.IsRequired();
b.Property<string>("ConnectionString")
.IsRequired()
.HasMaxLength(10000);
@@ -191,6 +190,9 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<uint?>("AutoUpdateInterval")
.IsRequired();
b.Property<ushort?>("ChatBotLimit")
.IsRequired();
b.Property<int>("ConfigurationType");
b.Property<string>("Name")
@@ -269,7 +271,8 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<DateTimeOffset?>("StartedAt")
.IsRequired();
b.Property<long>("StartedById");
b.Property<long?>("StartedById")
.IsRequired();
b.Property<DateTimeOffset?>("StoppedAt");
@@ -419,11 +422,11 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<DateTimeOffset>("MergedAt");
b.Property<long>("MergedById");
b.Property<int?>("Number")
b.Property<long?>("MergedById")
.IsRequired();
b.Property<int>("Number");
b.Property<long?>("PrimaryRevisionInformationId")
.IsRequired();
@@ -449,7 +452,7 @@ namespace Tgstation.Server.Host.Database.Migrations
modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
{
b.Property<long>("Id")
b.Property<long?>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AdministrationRights");
+8 -1
View File
@@ -7,6 +7,11 @@ namespace Tgstation.Server.Host.Models
/// <inheritdoc />
public sealed class ChatBot : Api.Models.Internal.ChatBot
{
/// <summary>
/// Default for <see cref="Api.Models.Internal.ChatBot.ChannelLimit"/>.
/// </summary>
public const ushort DefaultChannelLimit = 100;
/// <summary>
/// The <see cref="Api.Models.Instance.Id"/>
/// </summary>
@@ -34,7 +39,9 @@ namespace Tgstation.Server.Host.Models
Enabled = Enabled,
Provider = Provider,
Id = Id,
Name = Name
Name = Name,
ChannelLimit = ChannelLimit,
ReconnectionInterval = ReconnectionInterval
};
}
}
@@ -14,7 +14,7 @@
public long ChatSettingsId { get; set; }
/// <summary>
/// The <see cref="Models.ChatBot"/>
/// The <see cref="ChatBot"/>.
/// </summary>
public ChatBot ChatSettings { get; set; }
+7 -1
View File
@@ -7,6 +7,11 @@ namespace Tgstation.Server.Host.Models
/// </summary>
public sealed class Instance : Api.Models.Instance
{
/// <summary>
/// Default for <see cref="Api.Models.Instance.ChatBotLimit"/>.
/// </summary>
public const ushort DefaultChatBotLimit = 10;
/// <summary>
/// The <see cref="Models.DreamMakerSettings"/> for the <see cref="Instance"/>
/// </summary>
@@ -58,7 +63,8 @@ namespace Tgstation.Server.Host.Models
Id = Id,
Name = Name,
Path = Path,
Online = Online
Online = Online,
ChatBotLimit = ChatBotLimit
};
}
}
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Client;
using Tgstation.Server.Client.Components;
namespace Tgstation.Server.Tests.Instance
@@ -11,13 +13,17 @@ namespace Tgstation.Server.Tests.Instance
sealed class ChatTest
{
readonly IChatBotsClient chatClient;
readonly IInstanceManagerClient instanceClient;
readonly Api.Models.Instance metadata;
public ChatTest(IChatBotsClient chatBotsClient)
public ChatTest(IChatBotsClient chatClient, IInstanceManagerClient instanceClient, Api.Models.Instance metadata)
{
chatClient = chatBotsClient ?? throw new ArgumentNullException(nameof(chatBotsClient));
this.chatClient = chatClient ?? throw new ArgumentNullException(nameof(chatClient));
this.instanceClient = instanceClient ?? throw new ArgumentNullException(nameof(instanceClient));
this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
}
public async Task Run()
public async Task Run(CancellationToken cancellationToken)
{
var firstBot = new ChatBot
{
@@ -25,22 +31,23 @@ namespace Tgstation.Server.Tests.Instance
Enabled = false,
Name = "r4407",
Provider = ChatProvider.Discord,
ReconnectionInterval = 1
ReconnectionInterval = 1,
ChannelLimit = 1
};
firstBot = await chatClient.Create(firstBot, default);
firstBot = await chatClient.Create(firstBot, cancellationToken);
Assert.AreNotEqual(0, firstBot.Id);
var bots = await chatClient.List(default);
var bots = await chatClient.List(cancellationToken);
Assert.AreEqual(1, bots.Count);
Assert.AreEqual(firstBot.Id, bots.First().Id);
var retrievedBot = await chatClient.GetId(firstBot, default);
Assert.AreEqual(firstBot.Id, retrievedBot);
var retrievedBot = await chatClient.GetId(firstBot, cancellationToken);
Assert.AreEqual(firstBot.Id, retrievedBot.Id);
firstBot.Enabled = true;
var updatedBot = await chatClient.Update(firstBot, default);
var updatedBot = await chatClient.Update(firstBot, cancellationToken);
Assert.AreEqual(true, updatedBot.Enabled);
@@ -56,21 +63,55 @@ namespace Tgstation.Server.Tests.Instance
DiscordChannelId = channelId
}
};
updatedBot = await chatClient.Update(firstBot, default);
updatedBot = await chatClient.Update(firstBot, cancellationToken);
Assert.AreEqual(true, updatedBot.Enabled);
Assert.IsNotNull(updatedBot.Channels);
Assert.AreEqual(1, updatedBot.Channels.Count);
Assert.AreEqual(true, updatedBot.Channels.First().IsAdminChannel);
Assert.AreEqual(true, updatedBot.Channels.First().IsUpdatesChannel);
Assert.AreEqual(false, updatedBot.Channels.First().IsUpdatesChannel);
Assert.AreEqual(true, updatedBot.Channels.First().IsWatchdogChannel);
Assert.AreEqual("butt", updatedBot.Channels.First().Tag);
Assert.AreEqual(channelId, updatedBot.Channels.First().DiscordChannelId);
Assert.IsNull(updatedBot.Channels.First().IrcChannel);
await chatClient.Delete(firstBot, default);
bots = await chatClient.List(default);
await ApiAssert.ThrowsException<ConflictException>(() => chatClient.Create(new ChatBot
{
Name = "asdf",
ConnectionString = "asdf",
Provider = ChatProvider.Irc
}, cancellationToken), ErrorCode.ChatBotMax);
// We limited chat bots and channels to 1, try violating them
updatedBot.Channels.Add(
new ChatChannel
{
IsAdminChannel = true,
IsUpdatesChannel = false,
IsWatchdogChannel = true,
Tag = "butt",
DiscordChannelId = channelId
});
await ApiAssert.ThrowsException<ApiConflictException>(() => chatClient.Update(updatedBot, cancellationToken), ErrorCode.ChatBotMaxChannels);
var oldChannels = updatedBot.Channels;
updatedBot.Channels = null;
updatedBot.ChannelLimit = 0;
await ApiAssert.ThrowsException<ConflictException>(() => chatClient.Update(updatedBot, cancellationToken), ErrorCode.ChatBotMaxChannels);
updatedBot.Channels = oldChannels;
updatedBot.ChannelLimit = null;
await ApiAssert.ThrowsException<ConflictException>(() => chatClient.Update(updatedBot, cancellationToken), ErrorCode.ChatBotMaxChannels);
var instance = metadata.CloneMetadata();
instance.ChatBotLimit = 0;
await ApiAssert.ThrowsException<ConflictException>(() => instanceClient.Update(instance, cancellationToken), ErrorCode.ChatBotMax);
await chatClient.Delete(firstBot, cancellationToken);
bots = await chatClient.List(cancellationToken);
Assert.AreEqual(0, bots.Count);
}
}
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Client;
using Tgstation.Server.Client.Components;
namespace Tgstation.Server.Tests.Instance
@@ -8,20 +9,25 @@ namespace Tgstation.Server.Tests.Instance
sealed class InstanceTest
{
readonly IInstanceClient instanceClient;
readonly IInstanceManagerClient instanceManagerClient;
public InstanceTest(IInstanceClient instanceClient)
public InstanceTest(IInstanceClient instanceClient, IInstanceManagerClient instanceManagerClient)
{
this.instanceClient = instanceClient ?? throw new ArgumentNullException(nameof(instanceClient));
this.instanceManagerClient = instanceManagerClient ?? throw new ArgumentNullException(nameof(instanceManagerClient));
}
public async Task RunTests(CancellationToken cancellationToken)
{
var byondTests = new ByondTest(instanceClient.Byond, instanceClient.Jobs);
var configTests = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata);
var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs);
var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Metadata.CloneMetadata());
var configTest = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata);
var byondTest = byondTests.Run(cancellationToken);
await configTests.Run(cancellationToken).ConfigureAwait(false);
await byondTest.ConfigureAwait(false);
var byondTests = byondTest.Run(cancellationToken);
var chatTests = chatTest.Run(cancellationToken);
await configTest.Run(cancellationToken).ConfigureAwait(false);
await byondTests.ConfigureAwait(false);
await chatTests.ConfigureAwait(false);
}
}
}
@@ -30,7 +30,8 @@ namespace Tgstation.Server.Tests
{
Name = "TestInstance-" + ++counter,
Path = Path.Combine(testRootPath, Guid.NewGuid().ToString()),
Online = true
Online = true,
ChatBotLimit = 1
}, cancellationToken);
public async Task Run(CancellationToken cancellationToken)
@@ -115,7 +116,7 @@ namespace Tgstation.Server.Tests
Path = initialPath
}, cancellationToken), ErrorCode.InstanceRelocateOnline).ConfigureAwait(false);
var testSuite1 = new InstanceTest(instanceManagerClient.CreateClient(firstTest));
var testSuite1 = new InstanceTest(instanceManagerClient.CreateClient(firstTest), instanceManagerClient);
await testSuite1.RunTests(cancellationToken).ConfigureAwait(false);
//can regain permissions on instance without instance user