Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ArkBot/ArkBot.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@
<Compile Include="Commands\VoteCommand.cs" />
<Compile Include="Commands\WhoAmICommand.cs" />
<Compile Include="Commands\WildCommand.cs" />
<Compile Include="Configuration\Model\WebAppConfigSection.cs" />
<Compile Include="Configuration\Model\UsersInRoleConfig.cs" />
<Compile Include="Configuration\Model\UserRolesConfigSection.cs" />
<Compile Include="Configuration\Model\BackupsConfigSection.cs" />
Expand Down Expand Up @@ -868,7 +869,7 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\MapImages\EbenusAstrum.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\MapImages\Extinction.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
18 changes: 18 additions & 0 deletions ArkBot/Configuration/Model/AccessControlConfigSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,23 @@ namespace ArkBot.Configuration.Model
public class AccessControlConfigSection : Dictionary<string, AccessControlFeatureGroup>
{
public override string ToString() => "Access Control";

/// <summary>
/// Default settings for <see cref="Config.AccessControl"/>
/// </summary>
internal void SetupConfigDefaults()
{
GetOrAddNewWithPostAction("pages", (x) => x.SetupDefaults(new[] { "home", "server", "player", "admin-server" }));
GetOrAddNewWithPostAction("home", (x) => x.SetupDefaults(new[] { "myprofile", "serverlist", "serverdetails", "online", "externalresources" }));
GetOrAddNewWithPostAction("server", (x) => x.SetupDefaults(new[] { "players", "tribes", "wildcreatures", "wildcreatures-coords", "wildcreatures-basestats", "wildcreatures-ids", "wildcreatures-statistics" }));
GetOrAddNewWithPostAction("player", (x) => x.SetupDefaults(new[] { "profile", "profile-detailed", "creatures", "creatures-basestats", "creatures-ids", "creatures-cloud", "breeding", "crops", "generators", "kibbles-eggs", "tribelog" }));
GetOrAddNewWithPostAction("admin-server", (x) => x.SetupDefaults(new[] { "players", "tribes", "structures", "fertilized-eggs", "structures-rcon" }));
}

private void GetOrAddNewWithPostAction(string key, Action<AccessControlFeatureGroup> postAction)
{
if (!TryGetValue(key, out var fg)) Add(key, fg = new AccessControlFeatureGroup());
postAction(fg);
}
}
}
6 changes: 6 additions & 0 deletions ArkBot/Configuration/Model/AccessControlFeatureGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,11 @@ namespace ArkBot.Configuration.Model
public class AccessControlFeatureGroup : Dictionary<string, AccessControlFeatureRoles>
{
public override string ToString() => "Group";

internal void SetupDefaults(string[] keys)
{
foreach (var key in keys)
if (!ContainsKey(key)) Add(key, new AccessControlFeatureRoles(new[] { "" }));
}
}
}
3 changes: 3 additions & 0 deletions ArkBot/Configuration/Model/AccessControlFeatureRoles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@ namespace ArkBot.Configuration.Model
[InjectValidation]
public class AccessControlFeatureRoles : List<string>
{
public AccessControlFeatureRoles() { }

public AccessControlFeatureRoles(string[] roles) => AddRange(roles);
}
}
59 changes: 37 additions & 22 deletions ArkBot/Configuration/Model/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ public Config()
WebAppRedirectListenPrefix = new string[] { };
AccessControl = new AccessControlConfigSection();
Discord = new DiscordConfigSection();
WebApp = new WebAppConfigSection();
Backups = new BackupsConfigSection();

//Test = new Test1ConfigSection();
}

public void SetupDefaults()
{
AccessControl.SetupConfigDefaults();
}

// Required

[JsonProperty(PropertyName = "steamApiKey")]
Expand Down Expand Up @@ -111,15 +117,15 @@ public Config()
[ValidUrl(Optional = true, ErrorMessage = "{0} is not a valid URL")]
public string AppUrl { get; set; }

[JsonProperty(PropertyName = "arkMultipliers")]
[Display(Name = "ARK Multipliers", Description = "Server specific multipliers")]
[ConfigurationHelp(remarks: new[] { "ARK configuration multipliers used on your servers and required for accurate calculations throughout the application." })]
[JsonProperty(PropertyName = "webApp")]
[Display(Name = "Web App", Description = "Settings specific to the Web App feature")]
[ConfigurationHelp(remarks: new[] { "The Web App aims to provide important functions to players: dino listings, food-status, breeding info, statistics; and server admins: rcon-commands, server managing etc." })]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(3)]
[ExpandableObject]
[Required(ErrorMessage = "{0} is not set")]
[ValidateExpandable(ErrorMessage = "{0} contain field(s) that are invalid")]
public ArkMultipliersConfigSection ArkMultipliers { get; set; }
public WebAppConfigSection WebApp { get; set; }

[JsonProperty(PropertyName = "discord")]
[Display(Name = "Discord", Description = "Discord bot settings")]
Expand All @@ -131,11 +137,21 @@ public Config()
[ValidateExpandable(ErrorMessage = "{0} contain field(s) that are invalid")]
public DiscordConfigSection Discord { get; set; }

[JsonProperty(PropertyName = "arkMultipliers")]
[Display(Name = "ARK Multipliers", Description = "Server specific multipliers")]
[ConfigurationHelp(remarks: new[] { "ARK configuration multipliers used on your servers and required for accurate calculations throughout the application." })]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(5)]
[ExpandableObject]
[Required(ErrorMessage = "{0} is not set")]
[ValidateExpandable(ErrorMessage = "{0} contain field(s) that are invalid")]
public ArkMultipliersConfigSection ArkMultipliers { get; set; }

[JsonProperty(PropertyName = "userRoles")]
[Display(Name = "User Roles", Description = "Explicit steam user role assignment")]
[ConfigurationHelp(remarks: new[] { "Multiple roles can be configured and each contains a list of steam ids who belong to that role. Roles are used in Companion App (Web App) access control to grant access to specific pages/features." })]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(5)]
[PropertyOrder(6)]
[Editor(typeof(CustomCollectionEditor), typeof(CustomCollectionEditor))]
[Required(ErrorMessage = "{0} is not set")]
[ValidateCollection(ErrorMessage = "{0} contains item(s) that are invalid")]
Expand All @@ -145,15 +161,15 @@ public Config()
[Display(Name = "Access Control", Description = "Per-feature role based access control configuration")]
[ConfigurationHelp(remarks: new[] { "Contain a predefined set of pages/features to grant access to. Each page/feature contains a list of roles that have access to that particular resource. Roles are connected to steam users in the User Roles setting." })]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(6)]
[PropertyOrder(7)]
[Required(ErrorMessage = "{0} is not set")]
public AccessControlConfigSection AccessControl { get; set; }

[JsonProperty(PropertyName = "backups")]
[Display(Name = "Backups", Description = "Savegame backups")]
[ConfigurationHelp(remarks: new[] { "Settings specific to the savegame backup feature which optionally can be configured to take backups each time a savegame change is detected." })]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(7)]
[PropertyOrder(8)]
[ExpandableObject]
[Required(ErrorMessage = "{0} is not set")]
[ValidateExpandable(ErrorMessage = "{0} contain field(s) that are invalid")]
Expand All @@ -163,7 +179,7 @@ public Config()
[Display(Name = "Web App Redirect Listen Prefix(es)", Description = "Http listen prefix(es) that are redirected to BotUrl")]
[ConfigurationHelp(remarks: new[] { "Used to redirect alternate URLs to the actual Companion App (Web App) URL. Typically used to redirect HTTP requests to a secure HTTPS connection when SSL is enabled." }, Example = "http://+:80/")]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(8)]
[PropertyOrder(9)]
//todo: validate this listen prefix
public string[] WebAppRedirectListenPrefix { get; set; }

Expand All @@ -172,7 +188,7 @@ public Config()
[DefaultValue(@"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe")]
[ConfigurationHelp(remarks: new[] { "This is the path to the PowerShell executable on your system. It is used when `Use Powershell Output Redirect` is configured for a server instance to relay SteamCmd status back to ARK Bot." })]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(9)]
[PropertyOrder(10)]
[Editor(typeof(OpenFilePathEditor), typeof(OpenFilePathEditor))]
[OpenFilePathEditor(Filter = "Executable files (*.exe)|*.exe|All files (*.*)|*.*")]
[FileExists(ErrorMessage = "{0} is not set or the file path does not exist")]
Expand All @@ -187,7 +203,7 @@ public Config()
"For the SSL-certificate to be issued you need to prove that you control the domain name; the domain must be pointed to your public IP and port 80 must be open externally and available for the bot to bind locally.\r\n"
})]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(10)]
[PropertyOrder(11)]
[ExpandableObject]
[Required(ErrorMessage = "{0} is not set")]
[ValidateExpandable(ErrorMessage = "{0} contain field(s) that are invalid")]
Expand All @@ -203,7 +219,7 @@ public Config()
"[Learn more about listen prefixes](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364698(v=vs.85).aspx)\r\n"
})]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(11)]
[PropertyOrder(12)]
[MinLength(1, ErrorMessage = "{0} is not set")]
//todo: validate this listen prefix
[RegularExpressionCustom(@"^https://.*", IfMethod = nameof(IsSslEnabled), ErrorMessage = "{0} should be `https` when SSL is enabled")]
Expand All @@ -221,7 +237,7 @@ public Config()
"[Learn more about listen prefixes](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364698(v=vs.85).aspx)\r\n"
})]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(12)]
[PropertyOrder(13)]
[MinLength(1, ErrorMessage = "{0} is not set")]
//todo: validate this listen prefix
[RegularExpressionCustom(@"^https://.*", IfMethod = nameof(IsSslEnabled), ErrorMessage = "{0} should be `https` when SSL is enabled")]
Expand All @@ -232,11 +248,19 @@ public Config()
[Display(Name = "Temporary Files Directory", Description = "An existing directory path where temporary binary files can be stored (zip-files etc.)")]
[DefaultValue("%TEMP%\\ArkBot")]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(13)]
[PropertyOrder(14)]
[Editor(typeof(DirectoryPathEditor), typeof(DirectoryPathEditor))]
[DirectoryPathIsValid(ErrorMessage = "{0} is not set or the directory path is not valid")]
public string TempFileOutputDirPath { get; set; }

[JsonProperty(PropertyName = "hideUiOnStartup")]
[Display(Name = "Hide Ui On Startup", Description = "Hides the user interface on program startup")]
[DefaultValue(false)]
[ConfigurationHelp(remarks: new[] { "Allows hiding the user interface on program startup. The program can be accessed from the system tray icon." })]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(15)]
public bool HideUiOnStartup { get; set; }


// Optional Advanced

Expand Down Expand Up @@ -272,15 +296,6 @@ public Config()
[PropertyOrder(1)]
public bool AnonymizeWebApiData { get; set; }


[JsonProperty(PropertyName = "hideUiOnStartup")]
[Display(Name = "Hide Ui On Startup", Description = "Hides the user interface on program startup")]
[DefaultValue(false)]
[ConfigurationHelp(remarks: new[] { "Allows hiding the user interface on program startup. The program can be accessed from the system tray icon." })]
[Category(ConfigurationCategory.Optional)]
[PropertyOrder(14)]
public bool HideUiOnStartup { get; set; }

//[JsonProperty(PropertyName = "test")]
//[Display(Name = "Test", Description = "Test")]
//[Category(ConfigurationCategory.Debug)]
Expand Down
3 changes: 3 additions & 0 deletions ArkBot/Configuration/Model/IConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ namespace ArkBot.Configuration.Model
{
public interface IConfig
{
void SetupDefaults();

ArkMultipliersConfigSection ArkMultipliers { get; set; }
string BotName { get; set; }
string BotUrl { get; set; }
string AppUrl { get; set; }
string SteamApiKey { get; set; }
string TempFileOutputDirPath { get; set; }
WebAppConfigSection WebApp { get; set; }
DiscordConfigSection Discord { get; set; }
UserRolesConfigSection UserRoles { get; set; }
AccessControlConfigSection AccessControl { get; set; }
Expand Down
44 changes: 44 additions & 0 deletions ArkBot/Configuration/Model/WebAppConfigSection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ArkBot.Configuration;
using ArkBot.Configuration.Validation;
using Discord;
using Microsoft.IdentityModel;
using PropertyChanged;
using Validar;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using Xceed.Wpf.Toolkit.PropertyGrid.Editors;

namespace ArkBot.Configuration.Model
{
public enum WebAppTheme { Dark = 0, Light = 1 };

public class WebAppConfigSection
{
public WebAppConfigSection()
{
}

public override string ToString() => $"Web App";

[JsonProperty(PropertyName = "defaultTheme")]
[Display(Name = "Default Theme", Description = "Default theme to use in the Web App")]
public WebAppTheme DefaultTheme { get; set; } = WebAppTheme.Dark;

[JsonProperty(PropertyName = "tribeLogLimit")]
[Display(Name = "Tribe Log Limit", Description = "Limit for how many tribe logs are displayed in the Web App")]
[RangeOptional(1, 1000, Optional = false, ErrorMessage = "{0} must be between 1-1000")]
public int TribeLogLimit { get; set; } = 100;

[JsonProperty(PropertyName = "tribeLogColors")]
[Display(Name = "Tribe Log Colors", Description = "Enable colored tribe log entries in the Web App")]
public bool TribeLogColors { get; set; } = false;
}
}
20 changes: 19 additions & 1 deletion ArkBot/Data/TribeLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,29 @@ public class TribeLog
public int Day { get; set; }
public TimeSpan Time { get; set; }
public string Message { get; set; }
public string MessageHtml
{
get
{
return _rHtmlColors.Replace(Message, (m) =>
{
if (!float.TryParse(m.Groups["r"]?.Value, out float r)) r = 0;
if (!float.TryParse(m.Groups["g"]?.Value, out float g)) g = 0;
if (!float.TryParse(m.Groups["b"]?.Value, out float b)) b = 0;
if (!float.TryParse(m.Groups["a"]?.Value, out float a)) a = 0;

var f = (msg: m.Groups["msg"].Value.TrimEnd('!'), r: (int)Math.Round(r * 100), g: (int)Math.Round(g * 100), b: (int)Math.Round(b * 100), a: a);
return $@"<span style=""color: rgba({f.r}%,{f.g}%,{f.b}%,{f.a})"">{f.msg}</span>";
});
}
}
public string MessageUnformatted { get { return _rRemoveColors.Replace(Message, "").TrimEnd('!'); } }

public string Raw { get; set; }

private static Regex _rParseLog = new Regex(@"^Day\s+(?<day>\d+),\s+(?<hour>\d{2,2})\:(?<minute>\d{2,2})\:(?<second>\d{2,2})\:\s+(?<message>.+)$", RegexOptions.Singleline | RegexOptions.IgnoreCase);
private static Regex _rRemoveColors = new Regex(@"((\<RichColor Color\=\""\d+,\s*\d+,\s*\d+,\s*\d+\""\>)|(\<\/\>))", RegexOptions.Singleline | RegexOptions.IgnoreCase);
private static Regex _rHtmlColors = new Regex(@"\<RichColor Color\=\""(?<r>[\d\.]+),\s*(?<g>[\d\.]+),\s*(?<b>[\d\.]+),\s*(?<a>[\d\.]+)\""\>(?<msg>.+?)\<\/\>", RegexOptions.Singleline | RegexOptions.IgnoreCase);
private static Regex _rRemoveColors = new Regex(@"((\<RichColor Color\=\""[\d\.]+,\s*[\d\.]+,\s*[\d\.]+,\s*[\d\.]+\""\>)|(\<\/\>))", RegexOptions.Singleline | RegexOptions.IgnoreCase);

public string ToStringPretty()
{
Expand Down Expand Up @@ -65,6 +82,7 @@ public class TameWasKilledTribeLog : TribeLog
//"Day 12412, 19:59:51: <RichColor Color=\"1, 0, 0, 1\">Your Giganotosaurus - Lvl 65 (Giganotosaurus) was killed!</>",
//"Day 12411, 04:31:59: <RichColor Color=\"1, 0, 0, 1\">Your Argentavis B1 - Lvl 178 (Argentavis) was killed by a Megalodon - Lvl 72!</>",
//"Day 12437, 02:52:26: <RichColor Color=\"1, 0, 0, 1\">Tribemember Tobbe - Lvl 93 was killed by a Raptor - Lvl 56!</>", //we do not parse this
//"Day 12437, 02:52:26: <RichColor Color=\"0.85, 0.15, 0.25, 1\">HaYoon uploaded a Daeodon: Boss 84k - Lvl 256</>"

try
{
Expand Down
3 changes: 3 additions & 0 deletions ArkBot/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@
</Grid.RowDefinitions>
<Menu Grid.Row="0">
<MenuItem Header="File">
<MenuItem Header="Open Web App" Command="{Binding OpenWebAppCommand }" />
<Separator />
<MenuItem Header="Exit" Command="{Binding ExitCommand}" />
</MenuItem>
<MenuItem Header="Options">
<MenuItem Header="Reload partial config" Command="{Binding ReloadPartialConfig}" />
<Separator />
<MenuItem Header="Manually trigger server update" ItemsSource="{Binding ManuallyUpdateServers}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
Expand Down
3 changes: 3 additions & 0 deletions ArkBot/ViewModel/ConfigurationViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ private void OnSaveConfig(object parameter)
{
//if (!File.Exists(Constants.ConfigFilePath)) return;

// clear keyboard focus so that the configuration control triggers an update for the current field before saving
Keyboard.ClearFocus();

var result = MessageBox.Show("Are you sure you want to save this configuration?", "Save current configuration", MessageBoxButton.YesNo, MessageBoxImage.Question);

if (result != MessageBoxResult.Yes) return;
Expand Down
Loading