+++ /dev/null
-using Content.Shared.Administration.Logs;
-using Robust.Client.UserInterface;
-using Robust.Client.UserInterface.Controls;
-
-namespace Content.Client.Administration.UI.CustomControls;
-
-public sealed class AdminLogLabel : RichTextLabel
-{
- public AdminLogLabel(ref SharedAdminLog log, HSeparator separator)
- {
- Log = log;
- Separator = separator;
-
- SetMessage($"{log.Date:HH:mm:ss}: {log.Message}");
- OnVisibilityChanged += VisibilityChanged;
- }
-
- public SharedAdminLog Log { get; }
-
- public HSeparator Separator { get; }
-
- private void VisibilityChanged(Control control)
- {
- Separator.Visible = Visible;
- }
-
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
-
- OnVisibilityChanged -= VisibilityChanged;
- }
-}
using System.Linq;
+using System.Text.RegularExpressions;
using Content.Client.Administration.Systems;
using Content.Client.UserInterface.Controls;
using Content.Client.Verbs.UI;
using Content.Shared.Administration;
using Robust.Client.AutoGenerated;
-using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Input;
-using Robust.Shared.Utility;
namespace Content.Client.Administration.UI.CustomControls;
private void FilterList()
{
_sortedPlayerList.Clear();
+
+ Regex filterRegex;
+ // There is no neat way to handle invalid regex being submitted other than
+ // catching and ignoring the exception which gets thrown when it's invalid.
+ try
+ {
+ filterRegex = new Regex(FilterLineEdit.Text, RegexOptions.IgnoreCase);
+ }
+ catch (ArgumentException)
+ {
+ return;
+ }
+
foreach (var info in _playerList)
{
var displayName = $"{info.CharacterName} ({info.Username})";
if (info.IdentityName != info.CharacterName)
displayName += $" [{info.IdentityName}]";
if (!string.IsNullOrEmpty(FilterLineEdit.Text)
- && !displayName.ToLowerInvariant().Contains(FilterLineEdit.Text.Trim().ToLowerInvariant()))
+ && !filterRegex.IsMatch(displayName))
continue;
_sortedPlayerList.Add(info);
}
using Content.Client.Stylesheets;
using Content.Shared.Administration;
using Robust.Client.AutoGenerated;
-using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
-using Robust.Shared.Utility;
namespace Content.Client.Administration.UI.CustomControls;
<Control xmlns="https://spacestation14.io"
- xmlns:aui="clr-namespace:Content.Client.Administration.UI.CustomControls">
+ xmlns:aui="clr-namespace:Content.Client.Administration.UI.CustomControls"
+ xmlns:ui="clr-namespace:Content.Client.Options.UI">
<PanelContainer StyleClasses="BackgroundDark">
<BoxContainer Orientation="Horizontal">
<BoxContainer Orientation="Vertical">
<Button Name="ExportLogs" Access="Public" Text="{Loc admin-logs-export}"/>
<Button Name="PopOutButton" Access="Public" Text="{Loc admin-logs-pop-out}"/>
</BoxContainer>
+ <BoxContainer HorizontalExpand="True">
+ <Button Name="RenderRichTextButton" Access="Public" Text="{Loc admin-logs-render-rich-text}"
+ StyleClasses="OpenRight" ToggleMode="True"/>
+ <Button Name="RemoveMarkupButton" Access="Public" Text="{Loc admin-logs-remove-markup}"
+ StyleClasses="OpenLeft" ToggleMode="True"/>
+ <Control HorizontalExpand="True"/>
+ </BoxContainer>
<BoxContainer Orientation="Horizontal">
<LineEdit Name="LogSearch" Access="Public" StyleClasses="actionSearchBox"
HorizontalExpand="true" PlaceHolder="{Loc admin-logs-search-logs-placeholder}"/>
using System.Linq;
using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
using Content.Client.Administration.UI.CustomControls;
+using Content.Client.Administration.UI.Logs.Entries;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Robust.Client.AutoGenerated;
SelectAllPlayersButton.OnPressed += SelectAllPlayers;
SelectNoPlayersButton.OnPressed += SelectNoPlayers;
+ RenderRichTextButton.OnPressed += RenderRichTextChanged;
+ RemoveMarkupButton.OnPressed += RemoveMarkupChanged;
+
RoundSpinBox.IsValid = i => i > 0 && i <= CurrentRound;
RoundSpinBox.ValueChanged += RoundSpinBoxChanged;
RoundSpinBox.InitDefaultButtons();
private int CurrentRound { get; set; }
+ private Regex LogSearchRegex { get; set; } = new("");
+
public int SelectedRoundId => RoundSpinBox.Value;
public string Search => LogSearch.Text;
private int ShownLogs { get; set; }
private int TotalLogs { get; set; }
private int RoundLogs { get; set; }
public bool IncludeNonPlayerLogs { get; set; }
-
+ private bool RenderRichText { get; set; }
+ private bool RemoveMarkup { get; set; }
public HashSet<LogType> SelectedTypes { get; } = new();
public HashSet<Guid> SelectedPlayers { get; } = new();
private void LogSearchChanged(LineEditEventArgs args)
{
+ // This exception is thrown if the regex is invalid, which happens often, so we ignore it.
+ try
+ {
+ LogSearchRegex = new Regex(
+ "(" + LogSearch.Text + ")",
+ RegexOptions.IgnoreCase,
+ TimeSpan.FromSeconds(1));
+ }
+ catch (ArgumentException)
+ {
+ return;
+ }
+
UpdateLogs();
}
UpdateLogs();
}
+ private void RenderRichTextChanged(ButtonEventArgs args)
+ {
+ RenderRichText = args.Button.Pressed;
+
+ RemoveMarkup = RemoveMarkup && !RenderRichText;
+ RemoveMarkupButton.Pressed = RemoveMarkup;
+
+ UpdateLogs();
+ }
+
+ private void RemoveMarkupChanged(ButtonEventArgs args)
+ {
+ RemoveMarkup = args.Button.Pressed;
+
+ RenderRichText = !RemoveMarkup && RenderRichText;
+ RenderRichTextButton.Pressed = RenderRichText;
+
+ UpdateLogs();
+ }
+
public void SetTypesSelection(HashSet<LogType> selectedTypes, bool invert = false)
{
SelectedTypes.Clear();
foreach (var child in LogsContainer.Children)
{
- if (child is not AdminLogLabel log)
- {
+ if (child is not AdminLogEntry log)
continue;
- }
child.Visible = ShouldShowLog(log);
- if (child.Visible)
- {
- ShownLogs++;
- }
+ if (!child.Visible)
+ continue;
+
+ log.RenderResults(LogSearchRegex, RenderRichText, RemoveMarkup);
+ ShownLogs++;
}
UpdateCount();
button.Text.Contains(PlayerSearch.Text, StringComparison.OrdinalIgnoreCase);
}
- private bool LogMatchesPlayerFilter(AdminLogLabel label)
+ private bool LogMatchesPlayerFilter(AdminLogEntry entry)
{
- if (label.Log.Players.Length == 0)
+ if (entry.Log.Players.Length == 0)
return SelectedPlayers.Count == 0 || IncludeNonPlayerLogs;
- return SelectedPlayers.Overlaps(label.Log.Players);
+ return SelectedPlayers.Overlaps(entry.Log.Players);
}
- private bool ShouldShowLog(AdminLogLabel label)
+ private bool ShouldShowLog(AdminLogEntry entry)
{
// Check log type
- if (!SelectedTypes.Contains(label.Log.Type))
+ if (!SelectedTypes.Contains(entry.Log.Type))
return false;
// Check players
- if (!LogMatchesPlayerFilter(label))
+ if (!LogMatchesPlayerFilter(entry))
return false;
// Check impact
- if (!SelectedImpacts.Contains(label.Log.Impact))
+ if (!SelectedImpacts.Contains(entry.Log.Impact))
return false;
// Check search
- if (!label.Log.Message.Contains(LogSearch.Text, StringComparison.OrdinalIgnoreCase))
+ if (!LogSearchRegex.IsMatch(entry.Log.Message))
return false;
return true;
for (var i = 0; i < span.Length; i++)
{
ref var log = ref span[i];
- var separator = new HSeparator();
- var label = new AdminLogLabel(ref log, separator);
- label.Visible = ShouldShowLog(label);
-
+ var entry = new AdminLogEntry(ref log);
TotalLogs++;
- if (label.Visible)
- {
- ShownLogs++;
- }
-
- LogsContainer.AddChild(label);
- LogsContainer.AddChild(separator);
+ LogsContainer.AddChild(entry);
}
-
- UpdateCount();
+ UpdateLogs();
}
public void SetLogs(List<SharedAdminLog> logs)
SelectAllTypesButton.OnPressed -= SelectAllTypes;
SelectNoTypesButton.OnPressed -= SelectNoTypes;
+ IncludeNonPlayersButton.OnPressed -= IncludeNonPlayers;
IncludeNonPlayersButton.OnPressed -= IncludeNonPlayers;
SelectAllPlayersButton.OnPressed -= SelectAllPlayers;
SelectNoPlayersButton.OnPressed -= SelectNoPlayers;
using System.IO;
using System.Linq;
-using Content.Client.Administration.UI.CustomControls;
+using Content.Client.Administration.UI.Logs.Entries;
using Content.Client.Eui;
using Content.Shared.Administration.Logs;
using Content.Shared.Eui;
private const char CsvSeparator = ',';
private const string CsvQuote = "\"";
- private const string CsvHeader = "Date,ID,PlayerID,Severity,Type,Message";
+ private const string CsvHeader = "Date,ID,PlayerID,Severity,Type,Message,CurTime";
private ISawmill _sawmill;
await writer.WriteLineAsync(CsvHeader);
foreach (var child in LogsControl.LogsContainer.Children)
{
- if (child is not AdminLogLabel logLabel || !child.Visible)
+ if (child is not AdminLogEntry entry || !child.Visible)
continue;
- var log = logLabel.Log;
+ var log = entry.Log;
// Date
// I swear to god if someone adds ,s or "s to the other fields...
await writer.WriteAsync(CsvQuote);
await writer.WriteAsync(log.Message.Replace(CsvQuote, CsvQuote + CsvQuote));
await writer.WriteAsync(CsvQuote);
+ await writer.WriteAsync(CsvSeparator);
+ // CurTime
+ await writer.WriteAsync(log.CurTime.ToString());
await writer.WriteLineAsync();
}
--- /dev/null
+<BoxContainer xmlns="https://spacestation14.io"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
+ Orientation="Vertical">
+ <BoxContainer Margin="2">
+ <Collapsible>
+ <CollapsibleHeading Name="DetailsHeading" Access="Public">
+ <RichTextLabel Margin="20 0 0 0" Name="Message" MinSize="50 10" VerticalExpand="True" Access="Public" />
+ </CollapsibleHeading>
+ <CollapsibleBody Name="DetailsBody" Access="Public" />
+ </Collapsible>
+ </BoxContainer>
+ <cc:HSeparator/>
+</BoxContainer>
--- /dev/null
+using System.Text.RegularExpressions;
+using Content.Client.Message;
+using Content.Shared.Administration.Logs;
+using Content.Shared.CCVar;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Configuration;
+using Robust.Shared.Utility;
+
+namespace Content.Client.Administration.UI.Logs.Entries;
+
+[GenerateTypedNameReferences]
+public sealed partial class AdminLogEntry : BoxContainer
+{
+ private readonly IConfigurationManager _cfgManager;
+
+ public SharedAdminLog Log { get; }
+
+ private readonly string _rawMessage;
+
+ public AdminLogEntry(ref SharedAdminLog log)
+ {
+ _cfgManager = IoCManager.Resolve<IConfigurationManager>();
+
+ RobustXamlLoader.Load(this);
+
+ Log = log;
+
+ _rawMessage = $"{log.Date:HH:mm:ss}: {log.Message}";
+ Message.SetMessage(_rawMessage);
+
+ DetailsHeading.OnToggled += DetailsToggled;
+ }
+
+ /// <summary>
+ /// Sets text to be highlighted from a search result, and renders rich text, or removes all rich text markup.
+ /// </summary>
+ public void RenderResults(Regex highlightRegex, bool renderRichText, bool removeMarkup)
+ {
+ var color = _cfgManager.GetCVar(CCVars.AdminLogsHighlightColor);
+ var formattedMessage = renderRichText
+ ? _rawMessage
+ : removeMarkup
+ ? FormattedMessage.RemoveMarkupPermissive(_rawMessage)
+ : FormattedMessage.EscapeText(_rawMessage);
+
+ // Want to avoid highlighting smaller strings
+ if (highlightRegex.ToString().Length > 4)
+ {
+ try
+ {
+ formattedMessage = highlightRegex.Replace(formattedMessage, $"[color={color}]$1[/color]", 3);
+ }
+ catch (RegexMatchTimeoutException)
+ {
+ // if we time out then don't bother highlighting results
+ }
+ }
+
+ if (!FormattedMessage.TryFromMarkup(formattedMessage, out var outputMessage))
+ return;
+
+ Message.SetMessage(outputMessage);
+ }
+
+ /// <summary>
+ /// We perform some extra calculations in the dropdown, so we want to render that only when
+ /// the dropdown is actually opened.
+ /// This also removes itself from the event listener so it doesn't trigger again.
+ /// </summary>
+ private void DetailsToggled(BaseButton.ButtonToggledEventArgs args)
+ {
+ if (!args.Pressed || DetailsBody.ChildCount > 0)
+ return;
+ DetailsBody.AddChild(new AdminLogEntryDetails(Log));
+ DetailsHeading.OnToggled -= DetailsToggled;
+ }
+}
--- /dev/null
+<BoxContainer xmlns="https://spacestation14.io"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
+ xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
+ StyleClasses="BackgroundDark">
+ <BoxContainer Orientation="Vertical" Margin="4">
+ <BoxContainer Orientation="Vertical">
+ <Label Text="{Loc admin-logs-field-type}" Margin="0 0 4 0"/>
+ <Label Name="Type" Text="None" StyleClasses="LabelSecondaryColor" Access="Public"/>
+ </BoxContainer>
+ <cc:HSeparator/>
+ <BoxContainer Orientation="Vertical">
+ <Label Text="{Loc admin-logs-field-impact}" Margin="0 0 4 0"/>
+ <Label Name="Impact" Text="None" StyleClasses="LabelSecondaryColor" Access="Public"/>
+ </BoxContainer>
+ </BoxContainer>
+ <cc:VSeparator/>
+ <BoxContainer Orientation="Vertical" Margin="4">
+ <Label Text="{Loc admin-logs-field-time-header}"/>
+ <cc:HSeparator/>
+ <BoxContainer>
+ <Label Text="{Loc admin-logs-field-time-local}" Margin="0 0 4 0" HorizontalExpand="True"/>
+ <Label Name="LocalTime" Text="None" StyleClasses="LabelSecondaryColor" Access="Public" HorizontalExpand="True"/>
+ </BoxContainer>
+ <cc:HSeparator/>
+ <BoxContainer Orientation="Horizontal">
+ <Label Text="{Loc admin-logs-field-time-utc}" Margin="0 0 4 0" HorizontalExpand="True"/>
+ <Label Name="UTCTime" Text="None" StyleClasses="LabelSecondaryColor" Access="Public" HorizontalExpand="True"/>
+ </BoxContainer>
+ <cc:HSeparator/>
+ <BoxContainer Orientation="Horizontal">
+ <Label Text="{Loc admin-logs-field-time-round}" Margin="0 0 4 0" HorizontalExpand="True"/>
+ <Label Name="CurTime" Text="None" StyleClasses="LabelSecondaryColor" Access="Public" HorizontalExpand="True"/>
+ </BoxContainer>
+ </BoxContainer>
+ <cc:VSeparator/>
+ <BoxContainer Orientation="Vertical" Margin="4" HorizontalExpand="True">
+ <Label Text="{Loc admin-logs-field-players-header}"/>
+ <cc:HSeparator/>
+ <BoxContainer Orientation="Horizontal" Margin="4" VerticalExpand="True">
+ <controls:ListContainer Name="PlayerListContainer" Access="Public" HorizontalExpand="True"/>
+ </BoxContainer>
+ </BoxContainer>
+</BoxContainer>
--- /dev/null
+using System.Linq;
+using Content.Client.Administration.Systems;
+using Content.Client.Administration.UI.CustomControls;
+using Content.Client.UserInterface.Controls;
+using Content.Client.Verbs.UI;
+using Content.Shared.Administration.Logs;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Input;
+using Robust.Shared.Network;
+
+namespace Content.Client.Administration.UI.Logs.Entries;
+
+[GenerateTypedNameReferences]
+public sealed partial class AdminLogEntryDetails : BoxContainer
+{
+ private readonly AdminSystem _adminSystem;
+ private readonly IUserInterfaceManager _uiManager;
+ private readonly IEntityManager _entManager;
+
+ public AdminLogEntryDetails(SharedAdminLog log)
+ {
+ RobustXamlLoader.Load(this);
+ _entManager = IoCManager.Resolve<IEntityManager>();
+ _uiManager = IoCManager.Resolve<IUserInterfaceManager>();
+ _adminSystem = _entManager.System<AdminSystem>();
+
+ Type.Text = log.Type.ToString();
+ Impact.Text = log.Impact.ToString();
+
+ LocalTime.Text = $"{log.Date.ToLocalTime():HH:mm:ss}";
+ UTCTime.Text = $"{log.Date:HH:mm:ss}";
+ // TimeSpan and DateTime use different formatting string conventions for some completely logical reason
+ // that mere mortals such as myself will never be able to understand.
+ CurTime.Text = new TimeSpan(log.CurTime).ToString(@"hh\:mm\:ss");
+
+ PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown;
+ PlayerListContainer.GenerateItem += GenerateButton;
+ PopulateList(log.Players);
+ }
+
+ private void PopulateList(Guid[] players)
+ {
+ if (players.Length == 0)
+ return;
+
+ if (_adminSystem.PlayerList is not { } allPlayers || allPlayers.Count == 0)
+ return;
+
+ var listData = new List<PlayerListData>();
+ foreach (var playerGuid in players)
+ {
+ var netUserId = new NetUserId(playerGuid);
+
+ // Linq here is fine since this runs in response to admin input in the UI and
+ // this loop only tends to go through 1-4 iterations.
+ if (allPlayers.FirstOrDefault(player => player.SessionId == netUserId) is not { } playerInfo)
+ continue;
+
+ listData.Add(new PlayerListData(playerInfo));
+ }
+
+ if (listData.Count == 0)
+ return;
+
+ PlayerListContainer.PopulateList(listData);
+ }
+
+ private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data)
+ {
+ if (args == null || data is not PlayerListData { Info: var selectedPlayer })
+ return;
+
+ if (!(args.Function == EngineKeyFunctions.UIRightClick
+ || args.Function == EngineKeyFunctions.UIClick)
+ || selectedPlayer.NetEntity == null)
+ return;
+
+ _uiManager.GetUIController<VerbMenuUIController>().OpenVerbMenu(selectedPlayer.NetEntity.Value, true);
+ args.Handle();
+ }
+
+ private void GenerateButton(ListData data, ListContainerButton button)
+ {
+ if (data is not PlayerListData { Info: var info })
+ return;
+
+ var entryLabel = new Label();
+ entryLabel.Text = $"{info.CharacterName} ({info.Username})";
+ var entry = new BoxContainer();
+ entry.AddChild(entryLabel);
+
+ button.AddChild(entry);
+ button.AddStyleClass(ListContainer.StyleClassListContainerButton);
+ }
+}
_config.OnValueChanged(CCVars.AdminPlayerTabColorSetting, ColorSettingChanged, true);
_config.OnValueChanged(CCVars.AdminPlayerTabSymbolSetting, SymbolSettingChanged, true);
-
OverlayButton.OnPressed += OverlayButtonPressed;
ShowDisconnectedButton.OnPressed += ShowDisconnectedPressed;
SearchList.ItemKeyBindDown += (args, data) => OnEntryKeyBindDown?.Invoke(args, data);
RefreshPlayerList(_adminSystem.PlayerList);
-
}
#region Antag Overlay
<ui:OptionDropDown Name="DropDownPlayerTabSymbolSetting" Title="{Loc 'ui-options-admin-player-tab-symbol-setting'}" />
<ui:OptionDropDown Name="DropDownPlayerTabRoleSetting" Title="{Loc 'ui-options-admin-player-tab-role-setting'}" />
<ui:OptionDropDown Name="DropDownPlayerTabColorSetting" Title="{Loc 'ui-options-admin-player-tab-color-setting'}" />
+ <Label Text="{Loc 'ui-options-admin-logs-title'}"
+ StyleClasses="LabelKeyText"/>
+ <ui:OptionColorSlider Name="ColorSliderLogsHighlight" Title="{Loc 'ui-options-admin-logs-highlight-color'}" />
<Label Text="{Loc 'ui-options-admin-overlay-title'}"
StyleClasses="LabelKeyText"/>
<ui:OptionDropDown Name="DropDownOverlayAntagFormat" Title="{Loc 'ui-options-admin-overlay-antag-format'}" />
playerTabSymbolSettings.Add(new OptionDropDownCVar<string>.ValueOption(setting.ToString()!, Loc.GetString($"ui-options-admin-player-tab-symbol-setting-{setting.ToString()!.ToLower()}")));
}
+ Control.AddOptionColorSlider(CCVars.AdminLogsHighlightColor, ColorSliderLogsHighlight);
+
Control.AddOptionDropDown(CCVars.AdminPlayerTabSymbolSetting, DropDownPlayerTabSymbolSetting, playerTabSymbolSettings);
Control.AddOptionDropDown(CCVars.AdminPlayerTabRoleSetting, DropDownPlayerTabRoleSetting, playerTabRoleSettings);
Control.AddOptionDropDown(CCVars.AdminPlayerTabColorSetting, DropDownPlayerTabColorSetting, playerTabColorSettings);
--- /dev/null
+// <auto-generated />
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Text.Json;
+using Content.Server.Database;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NpgsqlTypes;
+
+#nullable disable
+
+namespace Content.Server.Database.Migrations.Postgres
+{
+ [DbContext(typeof(PostgresServerDbContext))]
+ [Migration("20250723055137_AdminLogsCurtime")]
+ partial class AdminLogsCurtime
+ {
+ /// <inheritdoc />
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.1")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Content.Server.Database.Admin", b =>
+ {
+ b.Property<Guid>("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.Property<int?>("AdminRankId")
+ .HasColumnType("integer")
+ .HasColumnName("admin_rank_id");
+
+ b.Property<bool>("Deadminned")
+ .HasColumnType("boolean")
+ .HasColumnName("deadminned");
+
+ b.Property<bool>("Suspended")
+ .HasColumnType("boolean")
+ .HasColumnName("suspended");
+
+ b.Property<string>("Title")
+ .HasColumnType("text")
+ .HasColumnName("title");
+
+ b.HasKey("UserId")
+ .HasName("PK_admin");
+
+ b.HasIndex("AdminRankId")
+ .HasDatabaseName("IX_admin_admin_rank_id");
+
+ b.ToTable("admin", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_flag_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<Guid>("AdminId")
+ .HasColumnType("uuid")
+ .HasColumnName("admin_id");
+
+ b.Property<string>("Flag")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("flag");
+
+ b.Property<bool>("Negative")
+ .HasColumnType("boolean")
+ .HasColumnName("negative");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_flag");
+
+ b.HasIndex("AdminId")
+ .HasDatabaseName("IX_admin_flag_admin_id");
+
+ b.HasIndex("Flag", "AdminId")
+ .IsUnique();
+
+ b.ToTable("admin_flag", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
+ {
+ b.Property<int>("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property<int>("Id")
+ .HasColumnType("integer")
+ .HasColumnName("admin_log_id");
+
+ b.Property<long>("CurTime")
+ .HasColumnType("bigint")
+ .HasColumnName("cur_time");
+
+ b.Property<DateTime>("Date")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("date");
+
+ b.Property<short>("Impact")
+ .HasColumnType("smallint")
+ .HasColumnName("impact");
+
+ b.Property<JsonDocument>("Json")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("json");
+
+ b.Property<string>("Message")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("message");
+
+ b.Property<int>("Type")
+ .HasColumnType("integer")
+ .HasColumnName("type");
+
+ b.HasKey("RoundId", "Id")
+ .HasName("PK_admin_log");
+
+ b.HasIndex("Date");
+
+ b.HasIndex("Message")
+ .HasAnnotation("Npgsql:TsVectorConfig", "english");
+
+ NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Message"), "GIN");
+
+ b.HasIndex("Type")
+ .HasDatabaseName("IX_admin_log_type");
+
+ b.ToTable("admin_log", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b =>
+ {
+ b.Property<int>("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property<int>("LogId")
+ .HasColumnType("integer")
+ .HasColumnName("log_id");
+
+ b.Property<Guid>("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.HasKey("RoundId", "LogId", "PlayerUserId")
+ .HasName("PK_admin_log_player");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_log_player_player_user_id");
+
+ b.ToTable("admin_log_player", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminMessage", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_messages_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<DateTime>("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property<Guid?>("CreatedById")
+ .HasColumnType("uuid")
+ .HasColumnName("created_by_id");
+
+ b.Property<bool>("Deleted")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted");
+
+ b.Property<DateTime?>("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property<Guid?>("DeletedById")
+ .HasColumnType("uuid")
+ .HasColumnName("deleted_by_id");
+
+ b.Property<bool>("Dismissed")
+ .HasColumnType("boolean")
+ .HasColumnName("dismissed");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property<DateTime?>("LastEditedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<string>("Message")
+ .IsRequired()
+ .HasMaxLength(4096)
+ .HasColumnType("character varying(4096)")
+ .HasColumnName("message");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property<bool>("Seen")
+ .HasColumnType("boolean")
+ .HasColumnName("seen");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_messages");
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("DeletedById");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_messages_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_admin_messages_round_id");
+
+ b.ToTable("admin_messages", null, t =>
+ {
+ t.HasCheckConstraint("NotDismissedAndSeen", "NOT dismissed OR seen");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminNote", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_notes_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<DateTime>("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property<Guid?>("CreatedById")
+ .HasColumnType("uuid")
+ .HasColumnName("created_by_id");
+
+ b.Property<bool>("Deleted")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted");
+
+ b.Property<DateTime?>("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property<Guid?>("DeletedById")
+ .HasColumnType("uuid")
+ .HasColumnName("deleted_by_id");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property<DateTime>("LastEditedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<string>("Message")
+ .IsRequired()
+ .HasMaxLength(4096)
+ .HasColumnType("character varying(4096)")
+ .HasColumnName("message");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property<bool>("Secret")
+ .HasColumnType("boolean")
+ .HasColumnName("secret");
+
+ b.Property<int>("Severity")
+ .HasColumnType("integer")
+ .HasColumnName("severity");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_notes");
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("DeletedById");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_notes_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_admin_notes_round_id");
+
+ b.ToTable("admin_notes", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_rank_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("name");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_rank");
+
+ b.ToTable("admin_rank", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_rank_flag_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<int>("AdminRankId")
+ .HasColumnType("integer")
+ .HasColumnName("admin_rank_id");
+
+ b.Property<string>("Flag")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("flag");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_rank_flag");
+
+ b.HasIndex("AdminRankId");
+
+ b.HasIndex("Flag", "AdminRankId")
+ .IsUnique();
+
+ b.ToTable("admin_rank_flag", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminWatchlist", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_watchlists_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<DateTime>("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property<Guid?>("CreatedById")
+ .HasColumnType("uuid")
+ .HasColumnName("created_by_id");
+
+ b.Property<bool>("Deleted")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted");
+
+ b.Property<DateTime?>("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property<Guid?>("DeletedById")
+ .HasColumnType("uuid")
+ .HasColumnName("deleted_by_id");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property<DateTime>("LastEditedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<string>("Message")
+ .IsRequired()
+ .HasMaxLength(4096)
+ .HasColumnType("character varying(4096)")
+ .HasColumnName("message");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_watchlists");
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("DeletedById");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_watchlists_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_admin_watchlists_round_id");
+
+ b.ToTable("admin_watchlists", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Antag", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("antag_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<string>("AntagName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("antag_name");
+
+ b.Property<int>("ProfileId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ b.HasKey("Id")
+ .HasName("PK_antag");
+
+ b.HasIndex("ProfileId", "AntagName")
+ .IsUnique();
+
+ b.ToTable("antag", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("assigned_user_id_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.Property<string>("UserName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("user_name");
+
+ b.HasKey("Id")
+ .HasName("PK_assigned_user_id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.HasIndex("UserName")
+ .IsUnique();
+
+ b.ToTable("assigned_user_id", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.BanTemplate", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("ban_template_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<bool>("AutoDelete")
+ .HasColumnType("boolean")
+ .HasColumnName("auto_delete");
+
+ b.Property<int>("ExemptFlags")
+ .HasColumnType("integer")
+ .HasColumnName("exempt_flags");
+
+ b.Property<bool>("Hidden")
+ .HasColumnType("boolean")
+ .HasColumnName("hidden");
+
+ b.Property<TimeSpan>("Length")
+ .HasColumnType("interval")
+ .HasColumnName("length");
+
+ b.Property<string>("Reason")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("reason");
+
+ b.Property<int>("Severity")
+ .HasColumnType("integer")
+ .HasColumnName("severity");
+
+ b.Property<string>("Title")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("title");
+
+ b.HasKey("Id")
+ .HasName("PK_ban_template");
+
+ b.ToTable("ban_template", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Blacklist", b =>
+ {
+ b.Property<Guid>("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.HasKey("UserId")
+ .HasName("PK_blacklist");
+
+ b.ToTable("blacklist", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("connection_log_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<IPAddress>("Address")
+ .IsRequired()
+ .HasColumnType("inet")
+ .HasColumnName("address");
+
+ b.Property<byte?>("Denied")
+ .HasColumnType("smallint")
+ .HasColumnName("denied");
+
+ b.Property<int>("ServerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0)
+ .HasColumnName("server_id");
+
+ b.Property<DateTime>("Time")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("time");
+
+ b.Property<float>("Trust")
+ .HasColumnType("real")
+ .HasColumnName("trust");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.Property<string>("UserName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("user_name");
+
+ b.HasKey("Id")
+ .HasName("PK_connection_log");
+
+ b.HasIndex("ServerId")
+ .HasDatabaseName("IX_connection_log_server_id");
+
+ b.HasIndex("Time");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("connection_log", null, t =>
+ {
+ t.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.IPIntelCache", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("ipintel_cache_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<IPAddress>("Address")
+ .IsRequired()
+ .HasColumnType("inet")
+ .HasColumnName("address");
+
+ b.Property<float>("Score")
+ .HasColumnType("real")
+ .HasColumnName("score");
+
+ b.Property<DateTime>("Time")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("time");
+
+ b.HasKey("Id")
+ .HasName("PK_ipintel_cache");
+
+ b.ToTable("ipintel_cache", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Job", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("job_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<string>("JobName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("job_name");
+
+ b.Property<int>("Priority")
+ .HasColumnType("integer")
+ .HasColumnName("priority");
+
+ b.Property<int>("ProfileId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ b.HasKey("Id")
+ .HasName("PK_job");
+
+ b.HasIndex("ProfileId");
+
+ b.HasIndex("ProfileId", "JobName")
+ .IsUnique();
+
+ b.HasIndex(new[] { "ProfileId" }, "IX_job_one_high_priority")
+ .IsUnique()
+ .HasFilter("priority = 3");
+
+ b.ToTable("job", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.PlayTime", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("play_time_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<Guid>("PlayerId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_id");
+
+ b.Property<TimeSpan>("TimeSpent")
+ .HasColumnType("interval")
+ .HasColumnName("time_spent");
+
+ b.Property<string>("Tracker")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("tracker");
+
+ b.HasKey("Id")
+ .HasName("PK_play_time");
+
+ b.HasIndex("PlayerId", "Tracker")
+ .IsUnique();
+
+ b.ToTable("play_time", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Player", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("player_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<DateTime>("FirstSeenTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("first_seen_time");
+
+ b.Property<DateTime?>("LastReadRules")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_read_rules");
+
+ b.Property<IPAddress>("LastSeenAddress")
+ .IsRequired()
+ .HasColumnType("inet")
+ .HasColumnName("last_seen_address");
+
+ b.Property<DateTime>("LastSeenTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_seen_time");
+
+ b.Property<string>("LastSeenUserName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("last_seen_user_name");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("PK_player");
+
+ b.HasAlternateKey("UserId")
+ .HasName("ak_player_user_id");
+
+ b.HasIndex("LastSeenUserName");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("player", null, t =>
+ {
+ t.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Preference", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("preference_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<string>("AdminOOCColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("admin_ooc_color");
+
+ b.PrimitiveCollection<List<string>>("ConstructionFavorites")
+ .IsRequired()
+ .HasColumnType("text[]")
+ .HasColumnName("construction_favorites");
+
+ b.Property<int>("SelectedCharacterSlot")
+ .HasColumnType("integer")
+ .HasColumnName("selected_character_slot");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("PK_preference");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("preference", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Profile", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<int>("Age")
+ .HasColumnType("integer")
+ .HasColumnName("age");
+
+ b.Property<string>("CharacterName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("char_name");
+
+ b.Property<string>("EyeColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("eye_color");
+
+ b.Property<string>("FacialHairColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("facial_hair_color");
+
+ b.Property<string>("FacialHairName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("facial_hair_name");
+
+ b.Property<string>("FlavorText")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("flavor_text");
+
+ b.Property<string>("Gender")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("gender");
+
+ b.Property<string>("HairColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("hair_color");
+
+ b.Property<string>("HairName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("hair_name");
+
+ b.Property<JsonDocument>("Markings")
+ .HasColumnType("jsonb")
+ .HasColumnName("markings");
+
+ b.Property<int>("PreferenceId")
+ .HasColumnType("integer")
+ .HasColumnName("preference_id");
+
+ b.Property<int>("PreferenceUnavailable")
+ .HasColumnType("integer")
+ .HasColumnName("pref_unavailable");
+
+ b.Property<string>("Sex")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("sex");
+
+ b.Property<string>("SkinColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("skin_color");
+
+ b.Property<int>("Slot")
+ .HasColumnType("integer")
+ .HasColumnName("slot");
+
+ b.Property<int>("SpawnPriority")
+ .HasColumnType("integer")
+ .HasColumnName("spawn_priority");
+
+ b.Property<string>("Species")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("species");
+
+ b.HasKey("Id")
+ .HasName("PK_profile");
+
+ b.HasIndex("PreferenceId")
+ .HasDatabaseName("IX_profile_preference_id");
+
+ b.HasIndex("Slot", "PreferenceId")
+ .IsUnique();
+
+ b.ToTable("profile", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("profile_loadout_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<string>("LoadoutName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("loadout_name");
+
+ b.Property<int>("ProfileLoadoutGroupId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_loadout_group_id");
+
+ b.HasKey("Id")
+ .HasName("PK_profile_loadout");
+
+ b.HasIndex("ProfileLoadoutGroupId");
+
+ b.ToTable("profile_loadout", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("profile_loadout_group_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<string>("GroupName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("group_name");
+
+ b.Property<int>("ProfileRoleLoadoutId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_role_loadout_id");
+
+ b.HasKey("Id")
+ .HasName("PK_profile_loadout_group");
+
+ b.HasIndex("ProfileRoleLoadoutId");
+
+ b.ToTable("profile_loadout_group", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("profile_role_loadout_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<string>("EntityName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("entity_name");
+
+ b.Property<int>("ProfileId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ b.Property<string>("RoleName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("role_name");
+
+ b.HasKey("Id")
+ .HasName("PK_profile_role_loadout");
+
+ b.HasIndex("ProfileId");
+
+ b.ToTable("profile_role_loadout", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.RoleWhitelist", b =>
+ {
+ b.Property<Guid>("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property<string>("RoleId")
+ .HasColumnType("text")
+ .HasColumnName("role_id");
+
+ b.HasKey("PlayerUserId", "RoleId")
+ .HasName("PK_role_whitelists");
+
+ b.ToTable("role_whitelists", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Round", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<int>("ServerId")
+ .HasColumnType("integer")
+ .HasColumnName("server_id");
+
+ b.Property<DateTime?>("StartDate")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("start_date");
+
+ b.HasKey("Id")
+ .HasName("PK_round");
+
+ b.HasIndex("ServerId")
+ .HasDatabaseName("IX_round_server_id");
+
+ b.HasIndex("StartDate");
+
+ b.ToTable("round", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Server", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("server_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("name");
+
+ b.HasKey("Id")
+ .HasName("PK_server");
+
+ b.ToTable("server", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBan", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("server_ban_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<NpgsqlInet?>("Address")
+ .HasColumnType("inet")
+ .HasColumnName("address");
+
+ b.Property<bool>("AutoDelete")
+ .HasColumnType("boolean")
+ .HasColumnName("auto_delete");
+
+ b.Property<DateTime>("BanTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("ban_time");
+
+ b.Property<Guid?>("BanningAdmin")
+ .HasColumnType("uuid")
+ .HasColumnName("banning_admin");
+
+ b.Property<int>("ExemptFlags")
+ .HasColumnType("integer")
+ .HasColumnName("exempt_flags");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property<bool>("Hidden")
+ .HasColumnType("boolean")
+ .HasColumnName("hidden");
+
+ b.Property<DateTime?>("LastEditedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<string>("Reason")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("reason");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property<int>("Severity")
+ .HasColumnType("integer")
+ .HasColumnName("severity");
+
+ b.HasKey("Id")
+ .HasName("PK_server_ban");
+
+ b.HasIndex("Address");
+
+ b.HasIndex("BanningAdmin");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_server_ban_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_server_ban_round_id");
+
+ b.ToTable("server_ban", null, t =>
+ {
+ t.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
+
+ t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBanExemption", b =>
+ {
+ b.Property<Guid>("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.Property<int>("Flags")
+ .HasColumnType("integer")
+ .HasColumnName("flags");
+
+ b.HasKey("UserId")
+ .HasName("PK_server_ban_exemption");
+
+ b.ToTable("server_ban_exemption", null, t =>
+ {
+ t.HasCheckConstraint("FlagsNotZero", "flags != 0");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBanHit", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("server_ban_hit_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<int>("BanId")
+ .HasColumnType("integer")
+ .HasColumnName("ban_id");
+
+ b.Property<int>("ConnectionId")
+ .HasColumnType("integer")
+ .HasColumnName("connection_id");
+
+ b.HasKey("Id")
+ .HasName("PK_server_ban_hit");
+
+ b.HasIndex("BanId")
+ .HasDatabaseName("IX_server_ban_hit_ban_id");
+
+ b.HasIndex("ConnectionId")
+ .HasDatabaseName("IX_server_ban_hit_connection_id");
+
+ b.ToTable("server_ban_hit", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("server_role_ban_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<NpgsqlInet?>("Address")
+ .HasColumnType("inet")
+ .HasColumnName("address");
+
+ b.Property<DateTime>("BanTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("ban_time");
+
+ b.Property<Guid?>("BanningAdmin")
+ .HasColumnType("uuid")
+ .HasColumnName("banning_admin");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property<bool>("Hidden")
+ .HasColumnType("boolean")
+ .HasColumnName("hidden");
+
+ b.Property<DateTime?>("LastEditedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<string>("Reason")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("reason");
+
+ b.Property<string>("RoleId")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("role_id");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property<int>("Severity")
+ .HasColumnType("integer")
+ .HasColumnName("severity");
+
+ b.HasKey("Id")
+ .HasName("PK_server_role_ban");
+
+ b.HasIndex("Address");
+
+ b.HasIndex("BanningAdmin");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_server_role_ban_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_server_role_ban_round_id");
+
+ b.ToTable("server_role_ban", null, t =>
+ {
+ t.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
+
+ t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("role_unban_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<int>("BanId")
+ .HasColumnType("integer")
+ .HasColumnName("ban_id");
+
+ b.Property<DateTime>("UnbanTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("unban_time");
+
+ b.Property<Guid?>("UnbanningAdmin")
+ .HasColumnType("uuid")
+ .HasColumnName("unbanning_admin");
+
+ b.HasKey("Id")
+ .HasName("PK_server_role_unban");
+
+ b.HasIndex("BanId")
+ .IsUnique();
+
+ b.ToTable("server_role_unban", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("unban_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<int>("BanId")
+ .HasColumnType("integer")
+ .HasColumnName("ban_id");
+
+ b.Property<DateTime>("UnbanTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("unban_time");
+
+ b.Property<Guid?>("UnbanningAdmin")
+ .HasColumnType("uuid")
+ .HasColumnName("unbanning_admin");
+
+ b.HasKey("Id")
+ .HasName("PK_server_unban");
+
+ b.HasIndex("BanId")
+ .IsUnique();
+
+ b.ToTable("server_unban", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Trait", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("trait_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<int>("ProfileId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ b.Property<string>("TraitName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("trait_name");
+
+ b.HasKey("Id")
+ .HasName("PK_trait");
+
+ b.HasIndex("ProfileId", "TraitName")
+ .IsUnique();
+
+ b.ToTable("trait", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.UploadedResourceLog", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("uploaded_resource_log_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+ b.Property<byte[]>("Data")
+ .IsRequired()
+ .HasColumnType("bytea")
+ .HasColumnName("data");
+
+ b.Property<DateTime>("Date")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("date");
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("path");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("PK_uploaded_resource_log");
+
+ b.ToTable("uploaded_resource_log", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Whitelist", b =>
+ {
+ b.Property<Guid>("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.HasKey("UserId")
+ .HasName("PK_whitelist");
+
+ b.ToTable("whitelist", (string)null);
+ });
+
+ modelBuilder.Entity("PlayerRound", b =>
+ {
+ b.Property<int>("PlayersId")
+ .HasColumnType("integer")
+ .HasColumnName("players_id");
+
+ b.Property<int>("RoundsId")
+ .HasColumnType("integer")
+ .HasColumnName("rounds_id");
+
+ b.HasKey("PlayersId", "RoundsId")
+ .HasName("PK_player_round");
+
+ b.HasIndex("RoundsId")
+ .HasDatabaseName("IX_player_round_rounds_id");
+
+ b.ToTable("player_round", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Admin", b =>
+ {
+ b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
+ .WithMany("Admins")
+ .HasForeignKey("AdminRankId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_admin_rank_admin_rank_id");
+
+ b.Navigation("AdminRank");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
+ {
+ b.HasOne("Content.Server.Database.Admin", "Admin")
+ .WithMany("Flags")
+ .HasForeignKey("AdminId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_flag_admin_admin_id");
+
+ b.Navigation("Admin");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
+ {
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany("AdminLogs")
+ .HasForeignKey("RoundId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_log_round_round_id");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("AdminLogs")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_log_player_player_player_user_id");
+
+ b.HasOne("Content.Server.Database.AdminLog", "Log")
+ .WithMany("Players")
+ .HasForeignKey("RoundId", "LogId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_log_player_admin_log_round_id_log_id");
+
+ b.Navigation("Log");
+
+ b.Navigation("Player");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminMessage", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminMessagesCreated")
+ .HasForeignKey("CreatedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_messages_player_created_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "DeletedBy")
+ .WithMany("AdminMessagesDeleted")
+ .HasForeignKey("DeletedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_messages_player_deleted_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminMessagesLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_messages_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("AdminMessagesReceived")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .HasConstraintName("FK_admin_messages_player_player_user_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_admin_messages_round_round_id");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Player");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminNote", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminNotesCreated")
+ .HasForeignKey("CreatedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_notes_player_created_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "DeletedBy")
+ .WithMany("AdminNotesDeleted")
+ .HasForeignKey("DeletedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_notes_player_deleted_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminNotesLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_notes_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("AdminNotesReceived")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .HasConstraintName("FK_admin_notes_player_player_user_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_admin_notes_round_round_id");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Player");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
+ {
+ b.HasOne("Content.Server.Database.AdminRank", "Rank")
+ .WithMany("Flags")
+ .HasForeignKey("AdminRankId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_rank_flag_admin_rank_admin_rank_id");
+
+ b.Navigation("Rank");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminWatchlist", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminWatchlistsCreated")
+ .HasForeignKey("CreatedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_watchlists_player_created_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "DeletedBy")
+ .WithMany("AdminWatchlistsDeleted")
+ .HasForeignKey("DeletedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_watchlists_player_deleted_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminWatchlistsLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_watchlists_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("AdminWatchlistsReceived")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .HasConstraintName("FK_admin_watchlists_player_player_user_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_admin_watchlists_round_round_id");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Player");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Antag", b =>
+ {
+ b.HasOne("Content.Server.Database.Profile", "Profile")
+ .WithMany("Antags")
+ .HasForeignKey("ProfileId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_antag_profile_profile_id");
+
+ b.Navigation("Profile");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
+ {
+ b.HasOne("Content.Server.Database.Server", "Server")
+ .WithMany("ConnectionLogs")
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .IsRequired()
+ .HasConstraintName("FK_connection_log_server_server_id");
+
+ b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
+ {
+ b1.Property<int>("ConnectionLogId")
+ .HasColumnType("integer")
+ .HasColumnName("connection_log_id");
+
+ b1.Property<byte[]>("Hwid")
+ .IsRequired()
+ .HasColumnType("bytea")
+ .HasColumnName("hwid");
+
+ b1.Property<int>("Type")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0)
+ .HasColumnName("hwid_type");
+
+ b1.HasKey("ConnectionLogId");
+
+ b1.ToTable("connection_log");
+
+ b1.WithOwner()
+ .HasForeignKey("ConnectionLogId")
+ .HasConstraintName("FK_connection_log_connection_log_connection_log_id");
+ });
+
+ b.Navigation("HWId");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Job", b =>
+ {
+ b.HasOne("Content.Server.Database.Profile", "Profile")
+ .WithMany("Jobs")
+ .HasForeignKey("ProfileId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_job_profile_profile_id");
+
+ b.Navigation("Profile");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Player", b =>
+ {
+ b.OwnsOne("Content.Server.Database.TypedHwid", "LastSeenHWId", b1 =>
+ {
+ b1.Property<int>("PlayerId")
+ .HasColumnType("integer")
+ .HasColumnName("player_id");
+
+ b1.Property<byte[]>("Hwid")
+ .IsRequired()
+ .HasColumnType("bytea")
+ .HasColumnName("last_seen_hwid");
+
+ b1.Property<int>("Type")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0)
+ .HasColumnName("last_seen_hwid_type");
+
+ b1.HasKey("PlayerId");
+
+ b1.ToTable("player");
+
+ b1.WithOwner()
+ .HasForeignKey("PlayerId")
+ .HasConstraintName("FK_player_player_player_id");
+ });
+
+ b.Navigation("LastSeenHWId");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Profile", b =>
+ {
+ b.HasOne("Content.Server.Database.Preference", "Preference")
+ .WithMany("Profiles")
+ .HasForeignKey("PreferenceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_profile_preference_preference_id");
+
+ b.Navigation("Preference");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b =>
+ {
+ b.HasOne("Content.Server.Database.ProfileLoadoutGroup", "ProfileLoadoutGroup")
+ .WithMany("Loadouts")
+ .HasForeignKey("ProfileLoadoutGroupId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_profile_loadout_profile_loadout_group_profile_loadout_group~");
+
+ b.Navigation("ProfileLoadoutGroup");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
+ {
+ b.HasOne("Content.Server.Database.ProfileRoleLoadout", "ProfileRoleLoadout")
+ .WithMany("Groups")
+ .HasForeignKey("ProfileRoleLoadoutId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_profile_loadout_group_profile_role_loadout_profile_role_loa~");
+
+ b.Navigation("ProfileRoleLoadout");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
+ {
+ b.HasOne("Content.Server.Database.Profile", "Profile")
+ .WithMany("Loadouts")
+ .HasForeignKey("ProfileId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_profile_role_loadout_profile_profile_id");
+
+ b.Navigation("Profile");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.RoleWhitelist", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("JobWhitelists")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_role_whitelists_player_player_user_id");
+
+ b.Navigation("Player");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Round", b =>
+ {
+ b.HasOne("Content.Server.Database.Server", "Server")
+ .WithMany("Rounds")
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_round_server_server_id");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBan", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminServerBansCreated")
+ .HasForeignKey("BanningAdmin")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_server_ban_player_banning_admin");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminServerBansLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_server_ban_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_server_ban_round_round_id");
+
+ b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
+ {
+ b1.Property<int>("ServerBanId")
+ .HasColumnType("integer")
+ .HasColumnName("server_ban_id");
+
+ b1.Property<byte[]>("Hwid")
+ .IsRequired()
+ .HasColumnType("bytea")
+ .HasColumnName("hwid");
+
+ b1.Property<int>("Type")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0)
+ .HasColumnName("hwid_type");
+
+ b1.HasKey("ServerBanId");
+
+ b1.ToTable("server_ban");
+
+ b1.WithOwner()
+ .HasForeignKey("ServerBanId")
+ .HasConstraintName("FK_server_ban_server_ban_server_ban_id");
+ });
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("HWId");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBanHit", b =>
+ {
+ b.HasOne("Content.Server.Database.ServerBan", "Ban")
+ .WithMany("BanHits")
+ .HasForeignKey("BanId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_server_ban_hit_server_ban_ban_id");
+
+ b.HasOne("Content.Server.Database.ConnectionLog", "Connection")
+ .WithMany("BanHits")
+ .HasForeignKey("ConnectionId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_server_ban_hit_connection_log_connection_id");
+
+ b.Navigation("Ban");
+
+ b.Navigation("Connection");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminServerRoleBansCreated")
+ .HasForeignKey("BanningAdmin")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_server_role_ban_player_banning_admin");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminServerRoleBansLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_server_role_ban_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_server_role_ban_round_round_id");
+
+ b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
+ {
+ b1.Property<int>("ServerRoleBanId")
+ .HasColumnType("integer")
+ .HasColumnName("server_role_ban_id");
+
+ b1.Property<byte[]>("Hwid")
+ .IsRequired()
+ .HasColumnType("bytea")
+ .HasColumnName("hwid");
+
+ b1.Property<int>("Type")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0)
+ .HasColumnName("hwid_type");
+
+ b1.HasKey("ServerRoleBanId");
+
+ b1.ToTable("server_role_ban");
+
+ b1.WithOwner()
+ .HasForeignKey("ServerRoleBanId")
+ .HasConstraintName("FK_server_role_ban_server_role_ban_server_role_ban_id");
+ });
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("HWId");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
+ {
+ b.HasOne("Content.Server.Database.ServerRoleBan", "Ban")
+ .WithOne("Unban")
+ .HasForeignKey("Content.Server.Database.ServerRoleUnban", "BanId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_server_role_unban_server_role_ban_ban_id");
+
+ b.Navigation("Ban");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
+ {
+ b.HasOne("Content.Server.Database.ServerBan", "Ban")
+ .WithOne("Unban")
+ .HasForeignKey("Content.Server.Database.ServerUnban", "BanId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_server_unban_server_ban_ban_id");
+
+ b.Navigation("Ban");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Trait", b =>
+ {
+ b.HasOne("Content.Server.Database.Profile", "Profile")
+ .WithMany("Traits")
+ .HasForeignKey("ProfileId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_trait_profile_profile_id");
+
+ b.Navigation("Profile");
+ });
+
+ modelBuilder.Entity("PlayerRound", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", null)
+ .WithMany()
+ .HasForeignKey("PlayersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_player_round_player_players_id");
+
+ b.HasOne("Content.Server.Database.Round", null)
+ .WithMany()
+ .HasForeignKey("RoundsId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_player_round_round_rounds_id");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Admin", b =>
+ {
+ b.Navigation("Flags");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
+ {
+ b.Navigation("Players");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
+ {
+ b.Navigation("Admins");
+
+ b.Navigation("Flags");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
+ {
+ b.Navigation("BanHits");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Player", b =>
+ {
+ b.Navigation("AdminLogs");
+
+ b.Navigation("AdminMessagesCreated");
+
+ b.Navigation("AdminMessagesDeleted");
+
+ b.Navigation("AdminMessagesLastEdited");
+
+ b.Navigation("AdminMessagesReceived");
+
+ b.Navigation("AdminNotesCreated");
+
+ b.Navigation("AdminNotesDeleted");
+
+ b.Navigation("AdminNotesLastEdited");
+
+ b.Navigation("AdminNotesReceived");
+
+ b.Navigation("AdminServerBansCreated");
+
+ b.Navigation("AdminServerBansLastEdited");
+
+ b.Navigation("AdminServerRoleBansCreated");
+
+ b.Navigation("AdminServerRoleBansLastEdited");
+
+ b.Navigation("AdminWatchlistsCreated");
+
+ b.Navigation("AdminWatchlistsDeleted");
+
+ b.Navigation("AdminWatchlistsLastEdited");
+
+ b.Navigation("AdminWatchlistsReceived");
+
+ b.Navigation("JobWhitelists");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Preference", b =>
+ {
+ b.Navigation("Profiles");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Profile", b =>
+ {
+ b.Navigation("Antags");
+
+ b.Navigation("Jobs");
+
+ b.Navigation("Loadouts");
+
+ b.Navigation("Traits");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
+ {
+ b.Navigation("Loadouts");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
+ {
+ b.Navigation("Groups");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Round", b =>
+ {
+ b.Navigation("AdminLogs");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Server", b =>
+ {
+ b.Navigation("ConnectionLogs");
+
+ b.Navigation("Rounds");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBan", b =>
+ {
+ b.Navigation("BanHits");
+
+ b.Navigation("Unban");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
+ {
+ b.Navigation("Unban");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
--- /dev/null
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Content.Server.Database.Migrations.Postgres
+{
+ /// <inheritdoc />
+ public partial class AdminLogsCurtime : Migration
+ {
+ /// <inheritdoc />
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn<long>(
+ name: "cur_time",
+ table: "admin_log",
+ type: "bigint",
+ nullable: false,
+ defaultValue: 0L);
+ }
+
+ /// <inheritdoc />
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "cur_time",
+ table: "admin_log");
+ }
+ }
+}
// <auto-generated />
using System;
+using System.Collections.Generic;
using System.Net;
using System.Text.Json;
using Content.Server.Database;
.HasColumnType("integer")
.HasColumnName("admin_log_id");
+ b.Property<long>("CurTime")
+ .HasColumnType("bigint")
+ .HasColumnName("cur_time");
+
b.Property<DateTime>("Date")
.HasColumnType("timestamp with time zone")
.HasColumnName("date");
.HasColumnType("text")
.HasColumnName("admin_ooc_color");
- b.PrimitiveCollection<string[]>("ConstructionFavorites")
+ b.PrimitiveCollection<List<string>>("ConstructionFavorites")
.IsRequired()
.HasColumnType("text[]")
.HasColumnName("construction_favorites");
--- /dev/null
+// <auto-generated />
+using System;
+using Content.Server.Database;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Content.Server.Database.Migrations.Sqlite
+{
+ [DbContext(typeof(SqliteServerDbContext))]
+ [Migration("20250723055127_AdminLogsCurtime")]
+ partial class AdminLogsCurtime
+ {
+ /// <inheritdoc />
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "9.0.1");
+
+ modelBuilder.Entity("Content.Server.Database.Admin", b =>
+ {
+ b.Property<Guid>("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("user_id");
+
+ b.Property<int?>("AdminRankId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("admin_rank_id");
+
+ b.Property<bool>("Deadminned")
+ .HasColumnType("INTEGER")
+ .HasColumnName("deadminned");
+
+ b.Property<bool>("Suspended")
+ .HasColumnType("INTEGER")
+ .HasColumnName("suspended");
+
+ b.Property<string>("Title")
+ .HasColumnType("TEXT")
+ .HasColumnName("title");
+
+ b.HasKey("UserId")
+ .HasName("PK_admin");
+
+ b.HasIndex("AdminRankId")
+ .HasDatabaseName("IX_admin_admin_rank_id");
+
+ b.ToTable("admin", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("admin_flag_id");
+
+ b.Property<Guid>("AdminId")
+ .HasColumnType("TEXT")
+ .HasColumnName("admin_id");
+
+ b.Property<string>("Flag")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("flag");
+
+ b.Property<bool>("Negative")
+ .HasColumnType("INTEGER")
+ .HasColumnName("negative");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_flag");
+
+ b.HasIndex("AdminId")
+ .HasDatabaseName("IX_admin_flag_admin_id");
+
+ b.HasIndex("Flag", "AdminId")
+ .IsUnique();
+
+ b.ToTable("admin_flag", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
+ {
+ b.Property<int>("RoundId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("round_id");
+
+ b.Property<int>("Id")
+ .HasColumnType("INTEGER")
+ .HasColumnName("admin_log_id");
+
+ b.Property<long>("CurTime")
+ .HasColumnType("INTEGER")
+ .HasColumnName("cur_time");
+
+ b.Property<DateTime>("Date")
+ .HasColumnType("TEXT")
+ .HasColumnName("date");
+
+ b.Property<sbyte>("Impact")
+ .HasColumnType("INTEGER")
+ .HasColumnName("impact");
+
+ b.Property<string>("Json")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("json");
+
+ b.Property<string>("Message")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("message");
+
+ b.Property<int>("Type")
+ .HasColumnType("INTEGER")
+ .HasColumnName("type");
+
+ b.HasKey("RoundId", "Id")
+ .HasName("PK_admin_log");
+
+ b.HasIndex("Date");
+
+ b.HasIndex("Type")
+ .HasDatabaseName("IX_admin_log_type");
+
+ b.ToTable("admin_log", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b =>
+ {
+ b.Property<int>("RoundId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("round_id");
+
+ b.Property<int>("LogId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("log_id");
+
+ b.Property<Guid>("PlayerUserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("player_user_id");
+
+ b.HasKey("RoundId", "LogId", "PlayerUserId")
+ .HasName("PK_admin_log_player");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_log_player_player_user_id");
+
+ b.ToTable("admin_log_player", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminMessage", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("admin_messages_id");
+
+ b.Property<DateTime>("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created_at");
+
+ b.Property<Guid?>("CreatedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("created_by_id");
+
+ b.Property<bool>("Deleted")
+ .HasColumnType("INTEGER")
+ .HasColumnName("deleted");
+
+ b.Property<DateTime?>("DeletedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("deleted_at");
+
+ b.Property<Guid?>("DeletedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("deleted_by_id");
+
+ b.Property<bool>("Dismissed")
+ .HasColumnType("INTEGER")
+ .HasColumnName("dismissed");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("expiration_time");
+
+ b.Property<DateTime?>("LastEditedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<string>("Message")
+ .IsRequired()
+ .HasMaxLength(4096)
+ .HasColumnType("TEXT")
+ .HasColumnName("message");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("TEXT")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("round_id");
+
+ b.Property<bool>("Seen")
+ .HasColumnType("INTEGER")
+ .HasColumnName("seen");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_messages");
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("DeletedById");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_messages_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_admin_messages_round_id");
+
+ b.ToTable("admin_messages", null, t =>
+ {
+ t.HasCheckConstraint("NotDismissedAndSeen", "NOT dismissed OR seen");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminNote", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("admin_notes_id");
+
+ b.Property<DateTime>("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created_at");
+
+ b.Property<Guid?>("CreatedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("created_by_id");
+
+ b.Property<bool>("Deleted")
+ .HasColumnType("INTEGER")
+ .HasColumnName("deleted");
+
+ b.Property<DateTime?>("DeletedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("deleted_at");
+
+ b.Property<Guid?>("DeletedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("deleted_by_id");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("expiration_time");
+
+ b.Property<DateTime>("LastEditedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<string>("Message")
+ .IsRequired()
+ .HasMaxLength(4096)
+ .HasColumnType("TEXT")
+ .HasColumnName("message");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("TEXT")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("round_id");
+
+ b.Property<bool>("Secret")
+ .HasColumnType("INTEGER")
+ .HasColumnName("secret");
+
+ b.Property<int>("Severity")
+ .HasColumnType("INTEGER")
+ .HasColumnName("severity");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_notes");
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("DeletedById");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_notes_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_admin_notes_round_id");
+
+ b.ToTable("admin_notes", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("admin_rank_id");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_rank");
+
+ b.ToTable("admin_rank", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("admin_rank_flag_id");
+
+ b.Property<int>("AdminRankId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("admin_rank_id");
+
+ b.Property<string>("Flag")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("flag");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_rank_flag");
+
+ b.HasIndex("AdminRankId");
+
+ b.HasIndex("Flag", "AdminRankId")
+ .IsUnique();
+
+ b.ToTable("admin_rank_flag", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminWatchlist", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("admin_watchlists_id");
+
+ b.Property<DateTime>("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created_at");
+
+ b.Property<Guid?>("CreatedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("created_by_id");
+
+ b.Property<bool>("Deleted")
+ .HasColumnType("INTEGER")
+ .HasColumnName("deleted");
+
+ b.Property<DateTime?>("DeletedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("deleted_at");
+
+ b.Property<Guid?>("DeletedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("deleted_by_id");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("expiration_time");
+
+ b.Property<DateTime>("LastEditedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<string>("Message")
+ .IsRequired()
+ .HasMaxLength(4096)
+ .HasColumnType("TEXT")
+ .HasColumnName("message");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("TEXT")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("round_id");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_watchlists");
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("DeletedById");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_watchlists_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_admin_watchlists_round_id");
+
+ b.ToTable("admin_watchlists", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Antag", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("antag_id");
+
+ b.Property<string>("AntagName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("antag_name");
+
+ b.Property<int>("ProfileId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_id");
+
+ b.HasKey("Id")
+ .HasName("PK_antag");
+
+ b.HasIndex("ProfileId", "AntagName")
+ .IsUnique();
+
+ b.ToTable("antag", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("assigned_user_id_id");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("user_id");
+
+ b.Property<string>("UserName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("user_name");
+
+ b.HasKey("Id")
+ .HasName("PK_assigned_user_id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.HasIndex("UserName")
+ .IsUnique();
+
+ b.ToTable("assigned_user_id", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.BanTemplate", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("ban_template_id");
+
+ b.Property<bool>("AutoDelete")
+ .HasColumnType("INTEGER")
+ .HasColumnName("auto_delete");
+
+ b.Property<int>("ExemptFlags")
+ .HasColumnType("INTEGER")
+ .HasColumnName("exempt_flags");
+
+ b.Property<bool>("Hidden")
+ .HasColumnType("INTEGER")
+ .HasColumnName("hidden");
+
+ b.Property<TimeSpan>("Length")
+ .HasColumnType("TEXT")
+ .HasColumnName("length");
+
+ b.Property<string>("Reason")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("reason");
+
+ b.Property<int>("Severity")
+ .HasColumnType("INTEGER")
+ .HasColumnName("severity");
+
+ b.Property<string>("Title")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("title");
+
+ b.HasKey("Id")
+ .HasName("PK_ban_template");
+
+ b.ToTable("ban_template", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Blacklist", b =>
+ {
+ b.Property<Guid>("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("user_id");
+
+ b.HasKey("UserId")
+ .HasName("PK_blacklist");
+
+ b.ToTable("blacklist", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("connection_log_id");
+
+ b.Property<string>("Address")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("address");
+
+ b.Property<byte?>("Denied")
+ .HasColumnType("INTEGER")
+ .HasColumnName("denied");
+
+ b.Property<int>("ServerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(0)
+ .HasColumnName("server_id");
+
+ b.Property<DateTime>("Time")
+ .HasColumnType("TEXT")
+ .HasColumnName("time");
+
+ b.Property<float>("Trust")
+ .HasColumnType("REAL")
+ .HasColumnName("trust");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("user_id");
+
+ b.Property<string>("UserName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("user_name");
+
+ b.HasKey("Id")
+ .HasName("PK_connection_log");
+
+ b.HasIndex("ServerId")
+ .HasDatabaseName("IX_connection_log_server_id");
+
+ b.HasIndex("Time");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("connection_log", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.IPIntelCache", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("ipintel_cache_id");
+
+ b.Property<string>("Address")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("address");
+
+ b.Property<float>("Score")
+ .HasColumnType("REAL")
+ .HasColumnName("score");
+
+ b.Property<DateTime>("Time")
+ .HasColumnType("TEXT")
+ .HasColumnName("time");
+
+ b.HasKey("Id")
+ .HasName("PK_ipintel_cache");
+
+ b.HasIndex("Address")
+ .IsUnique();
+
+ b.ToTable("ipintel_cache", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Job", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("job_id");
+
+ b.Property<string>("JobName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("job_name");
+
+ b.Property<int>("Priority")
+ .HasColumnType("INTEGER")
+ .HasColumnName("priority");
+
+ b.Property<int>("ProfileId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_id");
+
+ b.HasKey("Id")
+ .HasName("PK_job");
+
+ b.HasIndex("ProfileId");
+
+ b.HasIndex("ProfileId", "JobName")
+ .IsUnique();
+
+ b.HasIndex(new[] { "ProfileId" }, "IX_job_one_high_priority")
+ .IsUnique()
+ .HasFilter("priority = 3");
+
+ b.ToTable("job", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.PlayTime", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("play_time_id");
+
+ b.Property<Guid>("PlayerId")
+ .HasColumnType("TEXT")
+ .HasColumnName("player_id");
+
+ b.Property<TimeSpan>("TimeSpent")
+ .HasColumnType("TEXT")
+ .HasColumnName("time_spent");
+
+ b.Property<string>("Tracker")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("tracker");
+
+ b.HasKey("Id")
+ .HasName("PK_play_time");
+
+ b.HasIndex("PlayerId", "Tracker")
+ .IsUnique();
+
+ b.ToTable("play_time", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Player", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("player_id");
+
+ b.Property<DateTime>("FirstSeenTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("first_seen_time");
+
+ b.Property<DateTime?>("LastReadRules")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_read_rules");
+
+ b.Property<string>("LastSeenAddress")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("last_seen_address");
+
+ b.Property<DateTime>("LastSeenTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_seen_time");
+
+ b.Property<string>("LastSeenUserName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("last_seen_user_name");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("PK_player");
+
+ b.HasAlternateKey("UserId")
+ .HasName("ak_player_user_id");
+
+ b.HasIndex("LastSeenUserName");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("player", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Preference", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("preference_id");
+
+ b.Property<string>("AdminOOCColor")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("admin_ooc_color");
+
+ b.PrimitiveCollection<string>("ConstructionFavorites")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("construction_favorites");
+
+ b.Property<int>("SelectedCharacterSlot")
+ .HasColumnType("INTEGER")
+ .HasColumnName("selected_character_slot");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("PK_preference");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("preference", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Profile", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_id");
+
+ b.Property<int>("Age")
+ .HasColumnType("INTEGER")
+ .HasColumnName("age");
+
+ b.Property<string>("CharacterName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("char_name");
+
+ b.Property<string>("EyeColor")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("eye_color");
+
+ b.Property<string>("FacialHairColor")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("facial_hair_color");
+
+ b.Property<string>("FacialHairName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("facial_hair_name");
+
+ b.Property<string>("FlavorText")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("flavor_text");
+
+ b.Property<string>("Gender")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("gender");
+
+ b.Property<string>("HairColor")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("hair_color");
+
+ b.Property<string>("HairName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("hair_name");
+
+ b.Property<byte[]>("Markings")
+ .HasColumnType("jsonb")
+ .HasColumnName("markings");
+
+ b.Property<int>("PreferenceId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("preference_id");
+
+ b.Property<int>("PreferenceUnavailable")
+ .HasColumnType("INTEGER")
+ .HasColumnName("pref_unavailable");
+
+ b.Property<string>("Sex")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("sex");
+
+ b.Property<string>("SkinColor")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("skin_color");
+
+ b.Property<int>("Slot")
+ .HasColumnType("INTEGER")
+ .HasColumnName("slot");
+
+ b.Property<int>("SpawnPriority")
+ .HasColumnType("INTEGER")
+ .HasColumnName("spawn_priority");
+
+ b.Property<string>("Species")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("species");
+
+ b.HasKey("Id")
+ .HasName("PK_profile");
+
+ b.HasIndex("PreferenceId")
+ .HasDatabaseName("IX_profile_preference_id");
+
+ b.HasIndex("Slot", "PreferenceId")
+ .IsUnique();
+
+ b.ToTable("profile", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_loadout_id");
+
+ b.Property<string>("LoadoutName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("loadout_name");
+
+ b.Property<int>("ProfileLoadoutGroupId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_loadout_group_id");
+
+ b.HasKey("Id")
+ .HasName("PK_profile_loadout");
+
+ b.HasIndex("ProfileLoadoutGroupId");
+
+ b.ToTable("profile_loadout", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_loadout_group_id");
+
+ b.Property<string>("GroupName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("group_name");
+
+ b.Property<int>("ProfileRoleLoadoutId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_role_loadout_id");
+
+ b.HasKey("Id")
+ .HasName("PK_profile_loadout_group");
+
+ b.HasIndex("ProfileRoleLoadoutId");
+
+ b.ToTable("profile_loadout_group", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_role_loadout_id");
+
+ b.Property<string>("EntityName")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT")
+ .HasColumnName("entity_name");
+
+ b.Property<int>("ProfileId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_id");
+
+ b.Property<string>("RoleName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("role_name");
+
+ b.HasKey("Id")
+ .HasName("PK_profile_role_loadout");
+
+ b.HasIndex("ProfileId");
+
+ b.ToTable("profile_role_loadout", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.RoleWhitelist", b =>
+ {
+ b.Property<Guid>("PlayerUserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("player_user_id");
+
+ b.Property<string>("RoleId")
+ .HasColumnType("TEXT")
+ .HasColumnName("role_id");
+
+ b.HasKey("PlayerUserId", "RoleId")
+ .HasName("PK_role_whitelists");
+
+ b.ToTable("role_whitelists", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Round", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("round_id");
+
+ b.Property<int>("ServerId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("server_id");
+
+ b.Property<DateTime?>("StartDate")
+ .HasColumnType("TEXT")
+ .HasColumnName("start_date");
+
+ b.HasKey("Id")
+ .HasName("PK_round");
+
+ b.HasIndex("ServerId")
+ .HasDatabaseName("IX_round_server_id");
+
+ b.HasIndex("StartDate");
+
+ b.ToTable("round", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Server", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("server_id");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("name");
+
+ b.HasKey("Id")
+ .HasName("PK_server");
+
+ b.ToTable("server", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBan", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("server_ban_id");
+
+ b.Property<string>("Address")
+ .HasColumnType("TEXT")
+ .HasColumnName("address");
+
+ b.Property<bool>("AutoDelete")
+ .HasColumnType("INTEGER")
+ .HasColumnName("auto_delete");
+
+ b.Property<DateTime>("BanTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("ban_time");
+
+ b.Property<Guid?>("BanningAdmin")
+ .HasColumnType("TEXT")
+ .HasColumnName("banning_admin");
+
+ b.Property<int>("ExemptFlags")
+ .HasColumnType("INTEGER")
+ .HasColumnName("exempt_flags");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("expiration_time");
+
+ b.Property<bool>("Hidden")
+ .HasColumnType("INTEGER")
+ .HasColumnName("hidden");
+
+ b.Property<DateTime?>("LastEditedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("TEXT")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<string>("Reason")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("reason");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("round_id");
+
+ b.Property<int>("Severity")
+ .HasColumnType("INTEGER")
+ .HasColumnName("severity");
+
+ b.HasKey("Id")
+ .HasName("PK_server_ban");
+
+ b.HasIndex("Address");
+
+ b.HasIndex("BanningAdmin");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_server_ban_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_server_ban_round_id");
+
+ b.ToTable("server_ban", null, t =>
+ {
+ t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBanExemption", b =>
+ {
+ b.Property<Guid>("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("user_id");
+
+ b.Property<int>("Flags")
+ .HasColumnType("INTEGER")
+ .HasColumnName("flags");
+
+ b.HasKey("UserId")
+ .HasName("PK_server_ban_exemption");
+
+ b.ToTable("server_ban_exemption", null, t =>
+ {
+ t.HasCheckConstraint("FlagsNotZero", "flags != 0");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBanHit", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("server_ban_hit_id");
+
+ b.Property<int>("BanId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("ban_id");
+
+ b.Property<int>("ConnectionId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("connection_id");
+
+ b.HasKey("Id")
+ .HasName("PK_server_ban_hit");
+
+ b.HasIndex("BanId")
+ .HasDatabaseName("IX_server_ban_hit_ban_id");
+
+ b.HasIndex("ConnectionId")
+ .HasDatabaseName("IX_server_ban_hit_connection_id");
+
+ b.ToTable("server_ban_hit", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("server_role_ban_id");
+
+ b.Property<string>("Address")
+ .HasColumnType("TEXT")
+ .HasColumnName("address");
+
+ b.Property<DateTime>("BanTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("ban_time");
+
+ b.Property<Guid?>("BanningAdmin")
+ .HasColumnType("TEXT")
+ .HasColumnName("banning_admin");
+
+ b.Property<DateTime?>("ExpirationTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("expiration_time");
+
+ b.Property<bool>("Hidden")
+ .HasColumnType("INTEGER")
+ .HasColumnName("hidden");
+
+ b.Property<DateTime?>("LastEditedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_at");
+
+ b.Property<Guid?>("LastEditedById")
+ .HasColumnType("TEXT")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property<Guid?>("PlayerUserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("player_user_id");
+
+ b.Property<TimeSpan>("PlaytimeAtNote")
+ .HasColumnType("TEXT")
+ .HasColumnName("playtime_at_note");
+
+ b.Property<string>("Reason")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("reason");
+
+ b.Property<string>("RoleId")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("role_id");
+
+ b.Property<int?>("RoundId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("round_id");
+
+ b.Property<int>("Severity")
+ .HasColumnType("INTEGER")
+ .HasColumnName("severity");
+
+ b.HasKey("Id")
+ .HasName("PK_server_role_ban");
+
+ b.HasIndex("Address");
+
+ b.HasIndex("BanningAdmin");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_server_role_ban_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_server_role_ban_round_id");
+
+ b.ToTable("server_role_ban", null, t =>
+ {
+ t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("role_unban_id");
+
+ b.Property<int>("BanId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("ban_id");
+
+ b.Property<DateTime>("UnbanTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("unban_time");
+
+ b.Property<Guid?>("UnbanningAdmin")
+ .HasColumnType("TEXT")
+ .HasColumnName("unbanning_admin");
+
+ b.HasKey("Id")
+ .HasName("PK_server_role_unban");
+
+ b.HasIndex("BanId")
+ .IsUnique();
+
+ b.ToTable("server_role_unban", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("unban_id");
+
+ b.Property<int>("BanId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("ban_id");
+
+ b.Property<DateTime>("UnbanTime")
+ .HasColumnType("TEXT")
+ .HasColumnName("unban_time");
+
+ b.Property<Guid?>("UnbanningAdmin")
+ .HasColumnType("TEXT")
+ .HasColumnName("unbanning_admin");
+
+ b.HasKey("Id")
+ .HasName("PK_server_unban");
+
+ b.HasIndex("BanId")
+ .IsUnique();
+
+ b.ToTable("server_unban", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Trait", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("trait_id");
+
+ b.Property<int>("ProfileId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("profile_id");
+
+ b.Property<string>("TraitName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("trait_name");
+
+ b.HasKey("Id")
+ .HasName("PK_trait");
+
+ b.HasIndex("ProfileId", "TraitName")
+ .IsUnique();
+
+ b.ToTable("trait", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.UploadedResourceLog", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("uploaded_resource_log_id");
+
+ b.Property<byte[]>("Data")
+ .IsRequired()
+ .HasColumnType("BLOB")
+ .HasColumnName("data");
+
+ b.Property<DateTime>("Date")
+ .HasColumnType("TEXT")
+ .HasColumnName("date");
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasColumnName("path");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("PK_uploaded_resource_log");
+
+ b.ToTable("uploaded_resource_log", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Whitelist", b =>
+ {
+ b.Property<Guid>("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasColumnName("user_id");
+
+ b.HasKey("UserId")
+ .HasName("PK_whitelist");
+
+ b.ToTable("whitelist", (string)null);
+ });
+
+ modelBuilder.Entity("PlayerRound", b =>
+ {
+ b.Property<int>("PlayersId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("players_id");
+
+ b.Property<int>("RoundsId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("rounds_id");
+
+ b.HasKey("PlayersId", "RoundsId")
+ .HasName("PK_player_round");
+
+ b.HasIndex("RoundsId")
+ .HasDatabaseName("IX_player_round_rounds_id");
+
+ b.ToTable("player_round", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Admin", b =>
+ {
+ b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
+ .WithMany("Admins")
+ .HasForeignKey("AdminRankId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_admin_rank_admin_rank_id");
+
+ b.Navigation("AdminRank");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
+ {
+ b.HasOne("Content.Server.Database.Admin", "Admin")
+ .WithMany("Flags")
+ .HasForeignKey("AdminId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_flag_admin_admin_id");
+
+ b.Navigation("Admin");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
+ {
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany("AdminLogs")
+ .HasForeignKey("RoundId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_log_round_round_id");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("AdminLogs")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_log_player_player_player_user_id");
+
+ b.HasOne("Content.Server.Database.AdminLog", "Log")
+ .WithMany("Players")
+ .HasForeignKey("RoundId", "LogId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_log_player_admin_log_round_id_log_id");
+
+ b.Navigation("Log");
+
+ b.Navigation("Player");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminMessage", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminMessagesCreated")
+ .HasForeignKey("CreatedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_messages_player_created_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "DeletedBy")
+ .WithMany("AdminMessagesDeleted")
+ .HasForeignKey("DeletedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_messages_player_deleted_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminMessagesLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_messages_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("AdminMessagesReceived")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .HasConstraintName("FK_admin_messages_player_player_user_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_admin_messages_round_round_id");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Player");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminNote", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminNotesCreated")
+ .HasForeignKey("CreatedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_notes_player_created_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "DeletedBy")
+ .WithMany("AdminNotesDeleted")
+ .HasForeignKey("DeletedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_notes_player_deleted_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminNotesLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_notes_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("AdminNotesReceived")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .HasConstraintName("FK_admin_notes_player_player_user_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_admin_notes_round_round_id");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Player");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
+ {
+ b.HasOne("Content.Server.Database.AdminRank", "Rank")
+ .WithMany("Flags")
+ .HasForeignKey("AdminRankId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_admin_rank_flag_admin_rank_admin_rank_id");
+
+ b.Navigation("Rank");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminWatchlist", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminWatchlistsCreated")
+ .HasForeignKey("CreatedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_watchlists_player_created_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "DeletedBy")
+ .WithMany("AdminWatchlistsDeleted")
+ .HasForeignKey("DeletedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_watchlists_player_deleted_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminWatchlistsLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_admin_watchlists_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("AdminWatchlistsReceived")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .HasConstraintName("FK_admin_watchlists_player_player_user_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_admin_watchlists_round_round_id");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Player");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Antag", b =>
+ {
+ b.HasOne("Content.Server.Database.Profile", "Profile")
+ .WithMany("Antags")
+ .HasForeignKey("ProfileId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_antag_profile_profile_id");
+
+ b.Navigation("Profile");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
+ {
+ b.HasOne("Content.Server.Database.Server", "Server")
+ .WithMany("ConnectionLogs")
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .IsRequired()
+ .HasConstraintName("FK_connection_log_server_server_id");
+
+ b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
+ {
+ b1.Property<int>("ConnectionLogId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("connection_log_id");
+
+ b1.Property<byte[]>("Hwid")
+ .IsRequired()
+ .HasColumnType("BLOB")
+ .HasColumnName("hwid");
+
+ b1.Property<int>("Type")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(0)
+ .HasColumnName("hwid_type");
+
+ b1.HasKey("ConnectionLogId");
+
+ b1.ToTable("connection_log");
+
+ b1.WithOwner()
+ .HasForeignKey("ConnectionLogId")
+ .HasConstraintName("FK_connection_log_connection_log_connection_log_id");
+ });
+
+ b.Navigation("HWId");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Job", b =>
+ {
+ b.HasOne("Content.Server.Database.Profile", "Profile")
+ .WithMany("Jobs")
+ .HasForeignKey("ProfileId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_job_profile_profile_id");
+
+ b.Navigation("Profile");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Player", b =>
+ {
+ b.OwnsOne("Content.Server.Database.TypedHwid", "LastSeenHWId", b1 =>
+ {
+ b1.Property<int>("PlayerId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("player_id");
+
+ b1.Property<byte[]>("Hwid")
+ .IsRequired()
+ .HasColumnType("BLOB")
+ .HasColumnName("last_seen_hwid");
+
+ b1.Property<int>("Type")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(0)
+ .HasColumnName("last_seen_hwid_type");
+
+ b1.HasKey("PlayerId");
+
+ b1.ToTable("player");
+
+ b1.WithOwner()
+ .HasForeignKey("PlayerId")
+ .HasConstraintName("FK_player_player_player_id");
+ });
+
+ b.Navigation("LastSeenHWId");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Profile", b =>
+ {
+ b.HasOne("Content.Server.Database.Preference", "Preference")
+ .WithMany("Profiles")
+ .HasForeignKey("PreferenceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_profile_preference_preference_id");
+
+ b.Navigation("Preference");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b =>
+ {
+ b.HasOne("Content.Server.Database.ProfileLoadoutGroup", "ProfileLoadoutGroup")
+ .WithMany("Loadouts")
+ .HasForeignKey("ProfileLoadoutGroupId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_profile_loadout_profile_loadout_group_profile_loadout_group_id");
+
+ b.Navigation("ProfileLoadoutGroup");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
+ {
+ b.HasOne("Content.Server.Database.ProfileRoleLoadout", "ProfileRoleLoadout")
+ .WithMany("Groups")
+ .HasForeignKey("ProfileRoleLoadoutId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_profile_loadout_group_profile_role_loadout_profile_role_loadout_id");
+
+ b.Navigation("ProfileRoleLoadout");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
+ {
+ b.HasOne("Content.Server.Database.Profile", "Profile")
+ .WithMany("Loadouts")
+ .HasForeignKey("ProfileId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_profile_role_loadout_profile_profile_id");
+
+ b.Navigation("Profile");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.RoleWhitelist", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "Player")
+ .WithMany("JobWhitelists")
+ .HasForeignKey("PlayerUserId")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_role_whitelists_player_player_user_id");
+
+ b.Navigation("Player");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Round", b =>
+ {
+ b.HasOne("Content.Server.Database.Server", "Server")
+ .WithMany("Rounds")
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_round_server_server_id");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBan", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminServerBansCreated")
+ .HasForeignKey("BanningAdmin")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_server_ban_player_banning_admin");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminServerBansLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_server_ban_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_server_ban_round_round_id");
+
+ b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
+ {
+ b1.Property<int>("ServerBanId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("server_ban_id");
+
+ b1.Property<byte[]>("Hwid")
+ .IsRequired()
+ .HasColumnType("BLOB")
+ .HasColumnName("hwid");
+
+ b1.Property<int>("Type")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(0)
+ .HasColumnName("hwid_type");
+
+ b1.HasKey("ServerBanId");
+
+ b1.ToTable("server_ban");
+
+ b1.WithOwner()
+ .HasForeignKey("ServerBanId")
+ .HasConstraintName("FK_server_ban_server_ban_server_ban_id");
+ });
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("HWId");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBanHit", b =>
+ {
+ b.HasOne("Content.Server.Database.ServerBan", "Ban")
+ .WithMany("BanHits")
+ .HasForeignKey("BanId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_server_ban_hit_server_ban_ban_id");
+
+ b.HasOne("Content.Server.Database.ConnectionLog", "Connection")
+ .WithMany("BanHits")
+ .HasForeignKey("ConnectionId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_server_ban_hit_connection_log_connection_id");
+
+ b.Navigation("Ban");
+
+ b.Navigation("Connection");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", "CreatedBy")
+ .WithMany("AdminServerRoleBansCreated")
+ .HasForeignKey("BanningAdmin")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_server_role_ban_player_banning_admin");
+
+ b.HasOne("Content.Server.Database.Player", "LastEditedBy")
+ .WithMany("AdminServerRoleBansLastEdited")
+ .HasForeignKey("LastEditedById")
+ .HasPrincipalKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("FK_server_role_ban_player_last_edited_by_id");
+
+ b.HasOne("Content.Server.Database.Round", "Round")
+ .WithMany()
+ .HasForeignKey("RoundId")
+ .HasConstraintName("FK_server_role_ban_round_round_id");
+
+ b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
+ {
+ b1.Property<int>("ServerRoleBanId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("server_role_ban_id");
+
+ b1.Property<byte[]>("Hwid")
+ .IsRequired()
+ .HasColumnType("BLOB")
+ .HasColumnName("hwid");
+
+ b1.Property<int>("Type")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(0)
+ .HasColumnName("hwid_type");
+
+ b1.HasKey("ServerRoleBanId");
+
+ b1.ToTable("server_role_ban");
+
+ b1.WithOwner()
+ .HasForeignKey("ServerRoleBanId")
+ .HasConstraintName("FK_server_role_ban_server_role_ban_server_role_ban_id");
+ });
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("HWId");
+
+ b.Navigation("LastEditedBy");
+
+ b.Navigation("Round");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
+ {
+ b.HasOne("Content.Server.Database.ServerRoleBan", "Ban")
+ .WithOne("Unban")
+ .HasForeignKey("Content.Server.Database.ServerRoleUnban", "BanId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_server_role_unban_server_role_ban_ban_id");
+
+ b.Navigation("Ban");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
+ {
+ b.HasOne("Content.Server.Database.ServerBan", "Ban")
+ .WithOne("Unban")
+ .HasForeignKey("Content.Server.Database.ServerUnban", "BanId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_server_unban_server_ban_ban_id");
+
+ b.Navigation("Ban");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Trait", b =>
+ {
+ b.HasOne("Content.Server.Database.Profile", "Profile")
+ .WithMany("Traits")
+ .HasForeignKey("ProfileId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_trait_profile_profile_id");
+
+ b.Navigation("Profile");
+ });
+
+ modelBuilder.Entity("PlayerRound", b =>
+ {
+ b.HasOne("Content.Server.Database.Player", null)
+ .WithMany()
+ .HasForeignKey("PlayersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_player_round_player_players_id");
+
+ b.HasOne("Content.Server.Database.Round", null)
+ .WithMany()
+ .HasForeignKey("RoundsId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("FK_player_round_round_rounds_id");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Admin", b =>
+ {
+ b.Navigation("Flags");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
+ {
+ b.Navigation("Players");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
+ {
+ b.Navigation("Admins");
+
+ b.Navigation("Flags");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
+ {
+ b.Navigation("BanHits");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Player", b =>
+ {
+ b.Navigation("AdminLogs");
+
+ b.Navigation("AdminMessagesCreated");
+
+ b.Navigation("AdminMessagesDeleted");
+
+ b.Navigation("AdminMessagesLastEdited");
+
+ b.Navigation("AdminMessagesReceived");
+
+ b.Navigation("AdminNotesCreated");
+
+ b.Navigation("AdminNotesDeleted");
+
+ b.Navigation("AdminNotesLastEdited");
+
+ b.Navigation("AdminNotesReceived");
+
+ b.Navigation("AdminServerBansCreated");
+
+ b.Navigation("AdminServerBansLastEdited");
+
+ b.Navigation("AdminServerRoleBansCreated");
+
+ b.Navigation("AdminServerRoleBansLastEdited");
+
+ b.Navigation("AdminWatchlistsCreated");
+
+ b.Navigation("AdminWatchlistsDeleted");
+
+ b.Navigation("AdminWatchlistsLastEdited");
+
+ b.Navigation("AdminWatchlistsReceived");
+
+ b.Navigation("JobWhitelists");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Preference", b =>
+ {
+ b.Navigation("Profiles");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Profile", b =>
+ {
+ b.Navigation("Antags");
+
+ b.Navigation("Jobs");
+
+ b.Navigation("Loadouts");
+
+ b.Navigation("Traits");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
+ {
+ b.Navigation("Loadouts");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
+ {
+ b.Navigation("Groups");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Round", b =>
+ {
+ b.Navigation("AdminLogs");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Server", b =>
+ {
+ b.Navigation("ConnectionLogs");
+
+ b.Navigation("Rounds");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBan", b =>
+ {
+ b.Navigation("BanHits");
+
+ b.Navigation("Unban");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
+ {
+ b.Navigation("Unban");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
--- /dev/null
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Content.Server.Database.Migrations.Sqlite
+{
+ /// <inheritdoc />
+ public partial class AdminLogsCurtime : Migration
+ {
+ /// <inheritdoc />
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn<long>(
+ name: "cur_time",
+ table: "admin_log",
+ type: "INTEGER",
+ nullable: false,
+ defaultValue: 0L);
+ }
+
+ /// <inheritdoc />
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "cur_time",
+ table: "admin_log");
+ }
+ }
+}
.HasColumnType("INTEGER")
.HasColumnName("admin_log_id");
+ b.Property<long>("CurTime")
+ .HasColumnType("INTEGER")
+ .HasColumnName("cur_time");
+
b.Property<DateTime>("Date")
.HasColumnType("TEXT")
.HasColumnName("date");
[Required] public DateTime Date { get; set; }
+ /// <summary>
+ /// The current time in the round in ticks since the start of the round.
+ /// </summary>
+ public long CurTime { get; set; }
+
[Required] public string Message { get; set; } = default!;
[Required, Column(TypeName = "jsonb")] public JsonDocument Json { get; set; } = default!;
private void CacheLog(AdminLog log)
{
var players = log.Players.Select(player => player.PlayerUserId).ToArray();
- var record = new SharedAdminLog(log.Id, log.Type, log.Impact, log.Date, log.Message, players);
+ var record = new SharedAdminLog(log.Id, log.Type, log.Impact, log.Date, log.CurTime, log.Message, players);
CacheLog(record);
}
// Per round
private int _currentRoundId;
private int _currentLogId;
+ private TimeSpan _currentRoundStartTime;
private int NextLogId => Interlocked.Increment(ref _currentLogId);
private GameRunLevel _runLevel = GameRunLevel.PreRoundLobby;
public void RoundStarting(int id)
{
+ _currentRoundStartTime = _timing.CurTime;
_currentRoundId = id;
CacheNewRound();
}
Type = type,
Impact = impact,
Date = DateTime.UtcNow,
+ CurTime = (_timing.CurTime - _currentRoundStartTime).Ticks,
Message = message,
Json = json,
Players = new List<AdminLogPlayer>(players.Count)
players[i] = log.Players[i].PlayerUserId;
}
- yield return new SharedAdminLog(log.Id, log.Type, log.Impact, log.Date, log.Message, players);
+ yield return new SharedAdminLog(log.Id, log.Type, log.Impact, log.Date, log.CurTime, log.Message, players);
}
}
LogType Type,
LogImpact Impact,
DateTime Date,
+ long CurTime,
string Message,
Guid[] Players);
public static readonly CVarDef<bool> OutlineEnabled =
CVarDef.Create("outline.enabled", true, CVar.CLIENTONLY);
+ /// <summary>
+ /// Determines the color to use when highlighting search results in the admin log browser.
+ /// </summary>
+ public static readonly CVarDef<string> AdminLogsHighlightColor =
+ CVarDef.Create("ui.admin_logs_highlight_color", Color.Red.ToHex(), CVar.CLIENTONLY | CVar.ARCHIVE);
+
/// <summary>
/// Determines how antagonist status/roletype is displayed. Based on AdminOverlayAntagFormats enum
/// Binary: Roletypes of interest get an "ANTAG" label
admin-logs-search-logs-placeholder = Search Logs
admin-logs-refresh = Refresh
admin-logs-next = Next
+admin-logs-render-rich-text = Render Rich Text
+admin-logs-remove-markup = Remove Markup
+
+# Log Data Fields
+admin-logs-field-type = Type
+admin-logs-field-impact = Impact
+admin-logs-field-time-header = Time
+admin-logs-field-time-local = Local
+admin-logs-field-time-utc = UTC
+admin-logs-field-time-round = Round
+admin-logs-field-players-header = Players
+
+# Log Player Fields
+admin-logs-player-field-no-players = No Players
+admin-logs-player-field-not-in-round = Not in round.
ui-options-admin-player-tab-color-setting-roletype = Colorize all role types
ui-options-admin-player-tab-color-setting-both = Colorize both
+ui-options-admin-logs-title = Admin Logs
+ui-options-admin-logs-highlight-color = Highlight Color
+
ui-options-admin-overlay-title = Admin Overlay
ui-options-admin-overlay-antag-format = Antag label style
ui-options-admin-overlay-merge-distance = Stack merge distance
ui-options-admin-overlay-ghost-fade-distance = Ghost overlay fade range from mouse
ui-options-admin-overlay-ghost-hide-distance = Ghost overlay hide range from mouse
+