parent
3645cf53ff
commit
58bfd189d0
@ -431,7 +431,8 @@ namespace IW4MAdmin.Application
|
||||
{
|
||||
Name = cmd.Name,
|
||||
Alias = cmd.Alias,
|
||||
MinimumPermission = cmd.Permission
|
||||
MinimumPermission = cmd.Permission,
|
||||
AllowImpersonation = cmd.AllowImpersonation
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -144,6 +144,7 @@ namespace IW4MAdmin
|
||||
catch (CommandException e)
|
||||
{
|
||||
Logger.WriteInfo(e.Message);
|
||||
E.FailReason = GameEvent.EventFailReason.Invalid;
|
||||
}
|
||||
|
||||
if (C != null)
|
||||
@ -342,7 +343,7 @@ namespace IW4MAdmin
|
||||
return false;
|
||||
}
|
||||
|
||||
if (E.Origin.Level > EFClient.Permission.Moderator)
|
||||
if (E.Origin.Level > Permission.Moderator)
|
||||
{
|
||||
E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count));
|
||||
}
|
||||
@ -371,7 +372,7 @@ namespace IW4MAdmin
|
||||
Expires = expires,
|
||||
Offender = E.Target,
|
||||
Offense = E.Data,
|
||||
Punisher = E.Origin,
|
||||
Punisher = E.ImpersonationOrigin ?? E.Origin,
|
||||
When = DateTime.UtcNow,
|
||||
Link = E.Target.AliasLink
|
||||
};
|
||||
@ -388,7 +389,7 @@ namespace IW4MAdmin
|
||||
Expires = DateTime.UtcNow,
|
||||
Offender = E.Target,
|
||||
Offense = E.Data,
|
||||
Punisher = E.Origin,
|
||||
Punisher = E.ImpersonationOrigin ?? E.Origin,
|
||||
When = DateTime.UtcNow,
|
||||
Link = E.Target.AliasLink
|
||||
};
|
||||
@ -413,7 +414,7 @@ namespace IW4MAdmin
|
||||
Expires = DateTime.UtcNow,
|
||||
Offender = E.Target,
|
||||
Offense = E.Message,
|
||||
Punisher = E.Origin,
|
||||
Punisher = E.ImpersonationOrigin ?? E.Origin,
|
||||
Active = true,
|
||||
When = DateTime.UtcNow,
|
||||
Link = E.Target.AliasLink
|
||||
@ -432,28 +433,28 @@ namespace IW4MAdmin
|
||||
|
||||
else if (E.Type == GameEvent.EventType.TempBan)
|
||||
{
|
||||
await TempBan(E.Data, (TimeSpan)E.Extra, E.Target, E.Origin); ;
|
||||
await TempBan(E.Data, (TimeSpan)E.Extra, E.Target, E.ImpersonationOrigin ?? E.Origin); ;
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Ban)
|
||||
{
|
||||
bool isEvade = E.Extra != null ? (bool)E.Extra : false;
|
||||
await Ban(E.Data, E.Target, E.Origin, isEvade);
|
||||
await Ban(E.Data, E.Target, E.ImpersonationOrigin ?? E.Origin, isEvade);
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Unban)
|
||||
{
|
||||
await Unban(E.Data, E.Target, E.Origin);
|
||||
await Unban(E.Data, E.Target, E.ImpersonationOrigin ?? E.Origin);
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Kick)
|
||||
{
|
||||
await Kick(E.Data, E.Target, E.Origin);
|
||||
await Kick(E.Data, E.Target, E.ImpersonationOrigin ?? E.Origin);
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Warn)
|
||||
{
|
||||
await Warn(E.Data, E.Target, E.Origin);
|
||||
await Warn(E.Data, E.Target, E.ImpersonationOrigin ?? E.Origin);
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Disconnect)
|
||||
|
@ -19,6 +19,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands
|
||||
Alias = "rs";
|
||||
Permission = EFClient.Permission.User;
|
||||
RequiresTarget = false;
|
||||
//AllowImpersonation = true;
|
||||
}
|
||||
|
||||
public override async Task ExecuteAsync(GameEvent E)
|
||||
|
@ -117,5 +117,10 @@ namespace SharedLibraryCore
|
||||
/// Argument list for the command
|
||||
/// </summary>
|
||||
public CommandArgument[] Arguments { get; protected set; } = new CommandArgument[0];
|
||||
|
||||
/// <summary>
|
||||
/// indicates if this command allows impersonation (run as)
|
||||
/// </summary>
|
||||
public bool AllowImpersonation { get; set; }
|
||||
}
|
||||
}
|
||||
|
13
SharedLibraryCore/Commands/CommandExtensions.cs
Normal file
13
SharedLibraryCore/Commands/CommandExtensions.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibraryCore.Commands
|
||||
{
|
||||
public static class CommandExtensions
|
||||
{
|
||||
public static bool IsTargetingSelf(this GameEvent gameEvent) => gameEvent.Origin?.Equals(gameEvent.Target) ?? false;
|
||||
|
||||
public static bool CanPerformActionOnTarget(this GameEvent gameEvent) => gameEvent.Origin?.Level > gameEvent.Target?.Level;
|
||||
}
|
||||
}
|
@ -21,7 +21,8 @@ namespace SharedLibraryCore.Commands
|
||||
Command C = null;
|
||||
foreach (Command cmd in Manager.GetCommands())
|
||||
{
|
||||
if (cmd.Name == CommandString.ToLower() || cmd.Alias == CommandString.ToLower())
|
||||
if (cmd.Name.Equals(CommandString, StringComparison.OrdinalIgnoreCase) ||
|
||||
(cmd.Alias ?? "").Equals(CommandString, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
C = cmd;
|
||||
}
|
||||
@ -33,6 +34,12 @@ namespace SharedLibraryCore.Commands
|
||||
throw new CommandException($"{E.Origin} entered unknown command \"{CommandString}\"");
|
||||
}
|
||||
|
||||
if (!C.AllowImpersonation && E.ImpersonationOrigin != null)
|
||||
{
|
||||
E.ImpersonationOrigin.Tell(loc["COMMANDS_RUN_AS_FAIL"]);
|
||||
throw new CommandException($"Command {C.Name} cannot be run as another client");
|
||||
}
|
||||
|
||||
E.Data = E.Data.RemoveWords(1);
|
||||
String[] Args = E.Data.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
// todo: the code below can be cleaned up
|
||||
|
@ -1434,6 +1434,7 @@ namespace SharedLibraryCore.Commands
|
||||
Alias = "sp";
|
||||
Permission = Permission.Moderator;
|
||||
RequiresTarget = false;
|
||||
AllowImpersonation = true;
|
||||
Arguments = new[]
|
||||
{
|
||||
new CommandArgument()
|
||||
|
65
SharedLibraryCore/Commands/RunAsCommand.cs
Normal file
65
SharedLibraryCore/Commands/RunAsCommand.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibraryCore.Commands
|
||||
{
|
||||
public class RunAsCommand : Command
|
||||
{
|
||||
public RunAsCommand(CommandConfiguration config, ITranslationLookup lookup) : base(config, lookup)
|
||||
{
|
||||
Name = "runas";
|
||||
Description = lookup["COMMANDS_RUN_AS_DESC"];
|
||||
Alias = "ra";
|
||||
Permission = EFClient.Permission.Moderator;
|
||||
RequiresTarget = true;
|
||||
Arguments = new[]
|
||||
{
|
||||
new CommandArgument()
|
||||
{
|
||||
Name = lookup["COMMANDS_ARGS_COMMANDS"],
|
||||
Required = true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task ExecuteAsync(GameEvent E)
|
||||
{
|
||||
if (E.IsTargetingSelf())
|
||||
{
|
||||
E.Origin.Tell(_translationLookup["COMMANDS_RUN_AS_SELF"]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!E.CanPerformActionOnTarget())
|
||||
{
|
||||
E.Origin.Tell(_translationLookup["COMMANDS_RUN_AS_FAIL_PERM"]);
|
||||
return;
|
||||
}
|
||||
|
||||
string cmd = $"{Utilities.CommandPrefix}{E.Data}";
|
||||
var impersonatedCommandEvent = new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Command,
|
||||
Origin = E.Target,
|
||||
ImpersonationOrigin = E.Origin,
|
||||
Message = cmd,
|
||||
Data = cmd,
|
||||
Owner = E.Owner
|
||||
};
|
||||
E.Owner.Manager.GetEventHandler().AddEvent(impersonatedCommandEvent);
|
||||
|
||||
var result = await impersonatedCommandEvent.WaitAsync(Utilities.DefaultCommandTimeout, E.Owner.Manager.CancellationToken);
|
||||
var response = E.Owner.CommandResult.Where(c => c.ClientId == E.Target.ClientId).ToList();
|
||||
|
||||
// remove the added command response
|
||||
for (int i = 0; i < response.Count; i++)
|
||||
{
|
||||
E.Origin.Tell(_translationLookup["COMMANDS_RUN_AS_SUCCESS"].FormatExt(response[i].Response));
|
||||
E.Owner.CommandResult.Remove(response[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,5 +24,10 @@ namespace SharedLibraryCore.Configuration
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public Permission MinimumPermission { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the command can be run by another user (impersonation)
|
||||
/// </summary>
|
||||
public bool AllowImpersonation { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibraryCore.Database.Models
|
||||
{
|
||||
@ -22,6 +19,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
public int ChangeHistoryId { get; set; }
|
||||
public int OriginEntityId { get; set; }
|
||||
public int TargetEntityId { get; set; }
|
||||
public int? ImpersonationEntityId { get; set; }
|
||||
public ChangeType TypeOfChange { get; set; }
|
||||
public DateTime TimeChanged { get; set; } = DateTime.UtcNow;
|
||||
[MaxLength(128)]
|
||||
|
@ -227,6 +227,7 @@ namespace SharedLibraryCore
|
||||
public int? GameTime { get; set; }
|
||||
public EFClient Origin;
|
||||
public EFClient Target;
|
||||
public EFClient ImpersonationOrigin { get; set; }
|
||||
public Server Owner;
|
||||
public bool IsRemote { get; set; } = false;
|
||||
public object Extra { get; set; }
|
||||
@ -276,7 +277,7 @@ namespace SharedLibraryCore
|
||||
Owner?.Logger.WriteError("Waiting for event to complete timed out");
|
||||
Owner?.Logger.WriteDebug($"{Id}, {Type}, {Data}, {Extra}, {FailReason.ToString()}, {Message}, {Origin}, {Target}");
|
||||
#if DEBUG
|
||||
throw new Exception();
|
||||
//throw new Exception();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -44,5 +44,10 @@ namespace SharedLibraryCore.Interfaces
|
||||
/// Indicates if target is required
|
||||
/// </summary>
|
||||
bool RequiresTarget { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the commands can be run as another client
|
||||
/// </summary>
|
||||
bool AllowImpersonation { get; }
|
||||
}
|
||||
}
|
||||
|
919
SharedLibraryCore/Migrations/20200423225137_AddImpersonationIdToEFChangeHistory.Designer.cs
generated
Normal file
919
SharedLibraryCore/Migrations/20200423225137_AddImpersonationIdToEFChangeHistory.Designer.cs
generated
Normal file
@ -0,0 +1,919 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using SharedLibraryCore.Database;
|
||||
|
||||
namespace SharedLibraryCore.Migrations
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
[Migration("20200423225137_AddImpersonationIdToEFChangeHistory")]
|
||||
partial class AddImpersonationIdToEFChangeHistory
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "3.1.3");
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||
{
|
||||
b.Property<int>("SnapshotId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ClientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CurrentSessionLength")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("CurrentStrain")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("CurrentViewAngleId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Deaths")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("Distance")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("EloRating")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("HitDestinationId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("HitLocation")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("HitOriginId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("HitType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Hits")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Kills")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("LastStrainAngleId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("RecoilOffset")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("SessionAngleOffset")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("SessionAverageSnapValue")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("SessionSPM")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("SessionScore")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SessionSnapHits")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("StrainAngleBetween")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("TimeSinceLastEvent")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("WeaponId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("When")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("SnapshotId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.HasIndex("CurrentViewAngleId");
|
||||
|
||||
b.HasIndex("HitDestinationId");
|
||||
|
||||
b.HasIndex("HitOriginId");
|
||||
|
||||
b.HasIndex("LastStrainAngleId");
|
||||
|
||||
b.ToTable("EFACSnapshot");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
|
||||
{
|
||||
b.Property<int>("ACSnapshotVector3Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SnapshotId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Vector3Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("ACSnapshotVector3Id");
|
||||
|
||||
b.HasIndex("SnapshotId");
|
||||
|
||||
b.HasIndex("Vector3Id");
|
||||
|
||||
b.ToTable("EFACSnapshotVector3");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||
{
|
||||
b.Property<long>("KillId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AttackerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Damage")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("DeathOriginVector3Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DeathType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("Fraction")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("HitLoc")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsKill")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("KillOriginVector3Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Map")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("ServerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("VictimId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("ViewAnglesVector3Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("VisibilityPercentage")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("Weapon")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("When")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("KillId");
|
||||
|
||||
b.HasIndex("AttackerId");
|
||||
|
||||
b.HasIndex("DeathOriginVector3Id");
|
||||
|
||||
b.HasIndex("KillOriginVector3Id");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.HasIndex("VictimId");
|
||||
|
||||
b.HasIndex("ViewAnglesVector3Id");
|
||||
|
||||
b.ToTable("EFClientKills");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||
{
|
||||
b.Property<long>("MessageId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ClientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("ServerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("TimeSent")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("MessageId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.HasIndex("TimeSent");
|
||||
|
||||
b.ToTable("EFClientMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||
{
|
||||
b.Property<int>("RatingHistoryId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ClientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("RatingHistoryId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.ToTable("EFClientRatingHistory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||
{
|
||||
b.Property<int>("ClientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("ServerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("AverageRecoilOffset")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("AverageSnapValue")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("Deaths")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("EloRating")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("Kills")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("MaxStrain")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("RollingWeightedKDR")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("SPM")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("Skill")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("SnapHitCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("TimePlayed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("VisionAverage")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.HasKey("ClientId", "ServerId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("EFClientStatistics");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||
{
|
||||
b.Property<int>("HitLocationCountId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("EFClientStatisticsClientId")
|
||||
.HasColumnName("EFClientStatisticsClientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("EFClientStatisticsServerId")
|
||||
.HasColumnName("EFClientStatisticsServerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("HitCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<float>("HitOffsetAverage")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("Location")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<float>("MaxAngleDistance")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.HasKey("HitLocationCountId");
|
||||
|
||||
b.HasIndex("EFClientStatisticsServerId");
|
||||
|
||||
b.HasIndex("EFClientStatisticsClientId", "EFClientStatisticsServerId");
|
||||
|
||||
b.ToTable("EFHitLocationCounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||
{
|
||||
b.Property<int>("RatingId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ActivityAmount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Newest")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("Performance")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("Ranking")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RatingHistoryId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long?>("ServerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("When")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("RatingId");
|
||||
|
||||
b.HasIndex("RatingHistoryId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.HasIndex("Performance", "Ranking", "When");
|
||||
|
||||
b.ToTable("EFRating");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||
{
|
||||
b.Property<long>("ServerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("EndPoint")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("GameName")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Port")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("ServerId");
|
||||
|
||||
b.ToTable("EFServers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||
{
|
||||
b.Property<int>("StatisticId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("ServerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("TotalKills")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("TotalPlayTime")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("StatisticId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("EFServerStatistics");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||
{
|
||||
b.Property<int>("AliasId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("IPAddress")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("LinkId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(24);
|
||||
|
||||
b.Property<string>("SearchableName")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(24);
|
||||
|
||||
b.HasKey("AliasId");
|
||||
|
||||
b.HasIndex("IPAddress");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
b.HasIndex("Name");
|
||||
|
||||
b.HasIndex("SearchableName");
|
||||
|
||||
b.HasIndex("Name", "IPAddress")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("EFAlias");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
|
||||
{
|
||||
b.Property<int>("AliasLinkId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("AliasLinkId");
|
||||
|
||||
b.ToTable("EFAliasLinks");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
|
||||
{
|
||||
b.Property<int>("ChangeHistoryId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Comment")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(128);
|
||||
|
||||
b.Property<string>("CurrentValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("ImpersonationEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("OriginEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("PreviousValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("TargetEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("TimeChanged")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("TypeOfChange")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("ChangeHistoryId");
|
||||
|
||||
b.ToTable("EFChangeHistory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||
{
|
||||
b.Property<int>("ClientId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AliasLinkId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Connections")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CurrentAliasId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("FirstConnection")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("LastConnection")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Level")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Masked")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("NetworkId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordSalt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("TotalConnectionTime")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("ClientId");
|
||||
|
||||
b.HasIndex("AliasLinkId");
|
||||
|
||||
b.HasIndex("CurrentAliasId");
|
||||
|
||||
b.HasIndex("NetworkId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("EFClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||
{
|
||||
b.Property<int>("MetaId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ClientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Extra")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(32);
|
||||
|
||||
b.Property<DateTime>("Updated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("MetaId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.HasIndex("Key");
|
||||
|
||||
b.ToTable("EFMeta");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||
{
|
||||
b.Property<int>("PenaltyId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Active")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("AutomatedOffense")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("Expires")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsEvadedOffense")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("LinkId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("OffenderId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Offense")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("PunisherId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("When")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("PenaltyId");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
b.HasIndex("OffenderId");
|
||||
|
||||
b.HasIndex("PunisherId");
|
||||
|
||||
b.ToTable("EFPenalties");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||
{
|
||||
b.Property<int>("Vector3Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<float>("X")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<float>("Y")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<float>("Z")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.HasKey("Vector3Id");
|
||||
|
||||
b.ToTable("Vector3");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany()
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
|
||||
.WithMany()
|
||||
.HasForeignKey("CurrentViewAngleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
|
||||
.WithMany()
|
||||
.HasForeignKey("HitDestinationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
|
||||
.WithMany()
|
||||
.HasForeignKey("HitOriginId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
|
||||
.WithMany()
|
||||
.HasForeignKey("LastStrainAngleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
|
||||
{
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", "Snapshot")
|
||||
.WithMany("PredictedViewAngles")
|
||||
.HasForeignKey("SnapshotId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "Vector")
|
||||
.WithMany()
|
||||
.HasForeignKey("Vector3Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
||||
.WithMany()
|
||||
.HasForeignKey("AttackerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeathOriginVector3Id");
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
|
||||
.WithMany()
|
||||
.HasForeignKey("KillOriginVector3Id");
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
|
||||
.WithMany()
|
||||
.HasForeignKey("VictimId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
|
||||
.WithMany()
|
||||
.HasForeignKey("ViewAnglesVector3Id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany()
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany()
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany()
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany()
|
||||
.HasForeignKey("EFClientStatisticsClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("EFClientStatisticsServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", null)
|
||||
.WithMany("HitLocations")
|
||||
.HasForeignKey("EFClientStatisticsClientId", "EFClientStatisticsServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||
{
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
|
||||
.WithMany("Ratings")
|
||||
.HasForeignKey("RatingHistoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||
{
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||
.WithMany("Children")
|
||||
.HasForeignKey("LinkId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
|
||||
.WithMany()
|
||||
.HasForeignKey("AliasLinkId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
|
||||
.WithMany()
|
||||
.HasForeignKey("CurrentAliasId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany("Meta")
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||
.WithMany("ReceivedPenalties")
|
||||
.HasForeignKey("LinkId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
|
||||
.WithMany("ReceivedPenalties")
|
||||
.HasForeignKey("OffenderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
|
||||
.WithMany("AdministeredPenalties")
|
||||
.HasForeignKey("PunisherId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace SharedLibraryCore.Migrations
|
||||
{
|
||||
public partial class AddImpersonationIdToEFChangeHistory : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "ImpersonationEntityId",
|
||||
table: "EFChangeHistory",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ImpersonationEntityId",
|
||||
table: "EFChangeHistory");
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ namespace SharedLibraryCore.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "3.1.0");
|
||||
.HasAnnotation("ProductVersion", "3.1.3");
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||
{
|
||||
@ -511,6 +511,9 @@ namespace SharedLibraryCore.Migrations
|
||||
b.Property<string>("CurrentValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("ImpersonationEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("OriginEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@ -26,6 +26,7 @@ namespace SharedLibraryCore.Services
|
||||
{
|
||||
OriginEntityId = e.Origin.ClientId,
|
||||
TargetEntityId = e.Target.ClientId,
|
||||
ImpersonationEntityId = e.ImpersonationOrigin?.ClientId,
|
||||
TypeOfChange = EFChangeHistory.ChangeType.Ban,
|
||||
Comment = e.Data
|
||||
};
|
||||
@ -43,6 +44,7 @@ namespace SharedLibraryCore.Services
|
||||
{
|
||||
OriginEntityId = e.Origin.ClientId,
|
||||
TargetEntityId = e.Target?.ClientId ?? 0,
|
||||
ImpersonationEntityId = e.ImpersonationOrigin?.ClientId,
|
||||
Comment = "Executed command",
|
||||
CurrentValue = e.Message,
|
||||
TypeOfChange = EFChangeHistory.ChangeType.Command
|
||||
@ -53,6 +55,7 @@ namespace SharedLibraryCore.Services
|
||||
{
|
||||
OriginEntityId = e.Origin.ClientId,
|
||||
TargetEntityId = e.Target.ClientId,
|
||||
ImpersonationEntityId = e.ImpersonationOrigin?.ClientId,
|
||||
Comment = "Changed permission level",
|
||||
TypeOfChange = EFChangeHistory.ChangeType.Permission,
|
||||
CurrentValue = ((EFClient.Permission)e.Extra).ToString()
|
||||
|
@ -32,9 +32,9 @@ namespace SharedLibraryCore
|
||||
#endif
|
||||
public static Encoding EncodingType;
|
||||
public static Localization.Layout CurrentLocalization = new Localization.Layout(new Dictionary<string, string>());
|
||||
public static TimeSpan DefaultCommandTimeout = new TimeSpan(0, 0, 25);
|
||||
public static TimeSpan DefaultCommandTimeout { get; set; } = new TimeSpan(0, 0, 25);
|
||||
public static char[] DirectorySeparatorChars = new[] { '\\', '/' };
|
||||
|
||||
public static char CommandPrefix { get; set; } = '!';
|
||||
public static EFClient IW4MAdminClient(Server server = null)
|
||||
{
|
||||
return new EFClient()
|
||||
|
178
Tests/ApplicationTests/CommandTests.cs
Normal file
178
Tests/ApplicationTests/CommandTests.cs
Normal file
@ -0,0 +1,178 @@
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using IW4MAdmin;
|
||||
using FakeItEasy;
|
||||
using IW4MAdmin.Application.EventParsers;
|
||||
using System.Linq;
|
||||
using IW4MAdmin.Plugins.Stats.Models;
|
||||
using IW4MAdmin.Application.Helpers;
|
||||
using IW4MAdmin.Plugins.Stats.Config;
|
||||
using System.Collections.Generic;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using IW4MAdmin.Plugins.Stats.Helpers;
|
||||
using ApplicationTests.Fixtures;
|
||||
using System.Threading.Tasks;
|
||||
using SharedLibraryCore.Commands;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore;
|
||||
using ApplicationTests.Mocks;
|
||||
|
||||
namespace ApplicationTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class CommandTests
|
||||
{
|
||||
ILogger logger;
|
||||
private IServiceProvider serviceProvider;
|
||||
private ITranslationLookup transLookup;
|
||||
private CommandConfiguration cmdConfig;
|
||||
private MockEventHandler mockEventHandler;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
logger = A.Fake<ILogger>();
|
||||
cmdConfig = new CommandConfiguration();
|
||||
|
||||
serviceProvider = new ServiceCollection()
|
||||
.BuildBase()
|
||||
.BuildServiceProvider();
|
||||
|
||||
mockEventHandler = new MockEventHandler(true);
|
||||
A.CallTo(() => serviceProvider.GetRequiredService<IManager>().GetEventHandler())
|
||||
.Returns(mockEventHandler);
|
||||
|
||||
var mgr = serviceProvider.GetRequiredService<IManager>();
|
||||
transLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
|
||||
|
||||
A.CallTo(() => mgr.GetCommands())
|
||||
.Returns(new Command[]
|
||||
{
|
||||
new ImpersonatableCommand(cmdConfig, transLookup),
|
||||
new NonImpersonatableCommand(cmdConfig, transLookup)
|
||||
});
|
||||
|
||||
//Utilities.DefaultCommandTimeout = new TimeSpan(0, 0, 2);
|
||||
}
|
||||
|
||||
#region RUNAS
|
||||
[Test]
|
||||
public async Task Test_RunAsFailsOnSelf()
|
||||
{
|
||||
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||
var target = ClientGenerators.CreateBasicClient(server);
|
||||
|
||||
var gameEvent = new GameEvent()
|
||||
{
|
||||
Target = target,
|
||||
Origin = target
|
||||
};
|
||||
|
||||
await cmd.ExecuteAsync(gameEvent);
|
||||
|
||||
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Tell));
|
||||
Assert.IsEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Command));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Test_RunAsFailsOnHigherPrivilege()
|
||||
{
|
||||
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||
var target = ClientGenerators.CreateBasicClient(server);
|
||||
target.Level = EFClient.Permission.Administrator;
|
||||
var origin = ClientGenerators.CreateBasicClient(server);
|
||||
origin.NetworkId = 100;
|
||||
origin.Level = EFClient.Permission.Moderator;
|
||||
|
||||
var gameEvent = new GameEvent()
|
||||
{
|
||||
Target = target,
|
||||
Origin = origin
|
||||
};
|
||||
|
||||
await cmd.ExecuteAsync(gameEvent);
|
||||
|
||||
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Tell));
|
||||
Assert.IsEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Command));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Test_RunAsFailsOnSamePrivilege()
|
||||
{
|
||||
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||
var target = ClientGenerators.CreateBasicClient(server);
|
||||
target.Level = EFClient.Permission.Administrator;
|
||||
var origin = ClientGenerators.CreateBasicClient(server);
|
||||
origin.NetworkId = 100;
|
||||
origin.Level = EFClient.Permission.Administrator;
|
||||
|
||||
var gameEvent = new GameEvent()
|
||||
{
|
||||
Target = target,
|
||||
Origin = origin
|
||||
};
|
||||
|
||||
await cmd.ExecuteAsync(gameEvent);
|
||||
|
||||
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Tell));
|
||||
Assert.IsEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Command));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Test_RunAsFailsOnDisallowedCommand()
|
||||
{
|
||||
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||
var target = ClientGenerators.CreateBasicClient(server);
|
||||
target.Level = EFClient.Permission.Moderator;
|
||||
var origin = ClientGenerators.CreateBasicClient(server);
|
||||
origin.NetworkId = 100;
|
||||
origin.Level = EFClient.Permission.Administrator;
|
||||
|
||||
var gameEvent = new GameEvent()
|
||||
{
|
||||
Target = target,
|
||||
Origin = origin,
|
||||
Owner = server,
|
||||
Data = nameof(NonImpersonatableCommand)
|
||||
};
|
||||
|
||||
await cmd.ExecuteAsync(gameEvent);
|
||||
|
||||
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Tell));
|
||||
// failed when validating the command
|
||||
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Command && _event.FailReason == GameEvent.EventFailReason.Invalid));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Test_RunAsQueuesEventAndResponse()
|
||||
{
|
||||
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||
var target = ClientGenerators.CreateBasicClient(server);
|
||||
target.Level = EFClient.Permission.Moderator;
|
||||
var origin = ClientGenerators.CreateBasicClient(server);
|
||||
origin.NetworkId = 100;
|
||||
origin.Level = EFClient.Permission.Administrator;
|
||||
|
||||
var gameEvent = new GameEvent()
|
||||
{
|
||||
Target = target,
|
||||
Origin = origin,
|
||||
Data = nameof(ImpersonatableCommand),
|
||||
Owner = server
|
||||
};
|
||||
|
||||
await cmd.ExecuteAsync(gameEvent);
|
||||
|
||||
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Tell /*&& _event.Target == origin todo: fake the command result*/ ));
|
||||
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Command && !_event.Failed));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
36
Tests/ApplicationTests/Mocks/Commands.cs
Normal file
36
Tests/ApplicationTests/Mocks/Commands.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ApplicationTests.Mocks
|
||||
{
|
||||
class ImpersonatableCommand : Command
|
||||
{
|
||||
public ImpersonatableCommand(CommandConfiguration config, ITranslationLookup lookup) : base(config, lookup)
|
||||
{
|
||||
AllowImpersonation = true;
|
||||
Name = nameof(ImpersonatableCommand);
|
||||
}
|
||||
|
||||
public override Task ExecuteAsync(GameEvent E)
|
||||
{
|
||||
E.Origin.Tell("test");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
class NonImpersonatableCommand : Command
|
||||
{
|
||||
public NonImpersonatableCommand(CommandConfiguration config, ITranslationLookup lookup) : base(config, lookup)
|
||||
{
|
||||
Name = nameof(NonImpersonatableCommand);
|
||||
}
|
||||
|
||||
public override Task ExecuteAsync(GameEvent E)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,10 +7,22 @@ namespace ApplicationTests.Mocks
|
||||
class MockEventHandler : IEventHandler
|
||||
{
|
||||
public IList<GameEvent> Events = new List<GameEvent>();
|
||||
private readonly bool _autoExecute;
|
||||
|
||||
public MockEventHandler(bool autoExecute = false)
|
||||
{
|
||||
_autoExecute = autoExecute;
|
||||
}
|
||||
|
||||
public void AddEvent(GameEvent gameEvent)
|
||||
{
|
||||
Events.Add(gameEvent);
|
||||
|
||||
if (_autoExecute)
|
||||
{
|
||||
gameEvent.Owner?.ExecuteEvent(gameEvent);
|
||||
gameEvent.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user