Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ private IBotCommand GetFilledInstance(Type commandType, BotCommandTemplate templ
var instance = Activator.CreateInstance(commandType);
foreach (var property in commandType.GetProperties())
{
var propertyType = template.Properties.First(x => x.Name == property.Name).Type;
var isList = propertyType == BotCommandPropertyType.List;
var propertyCommandType = template.Properties.First(x => x.Name == property.Name).Type;
var isList = propertyCommandType == BotCommandPropertyType.List;
var value = getValueByName.Invoke(property.Name, isList);
if (string.IsNullOrWhiteSpace(value as string) && !isList)
{
Expand All @@ -62,8 +62,8 @@ private IBotCommand GetFilledInstance(Type commandType, BotCommandTemplate templ
}
if (value is string valueString)
{
var convertedType = this._botCommandPropertyConversionService.ConvertType(valueString, propertyType);
property.SetValue(instance, convertedType);
var convertedValue = this._botCommandPropertyConversionService.ConvertType(valueString, propertyCommandType, property.PropertyType);
property.SetValue(instance, convertedValue);
}
}
return (IBotCommand)instance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ namespace Devscord.DiscordFramework.Commands.Services
{
public interface IBotCommandsPropertyConversionService
{
object ConvertType(string value, BotCommandPropertyType type);
object ConvertType(string value, BotCommandPropertyType commandType, Type propertyType);
}

public class BotCommandsPropertyConversionService : IBotCommandsPropertyConversionService
{
private readonly Regex _exTime = new Regex(@"(?<Value>\d+)(?<Unit>(ms|d|h|m|s))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private readonly Regex _exMention = new Regex(@"\d+", RegexOptions.Compiled);

public object ConvertType(string value, BotCommandPropertyType type)
public object ConvertType(string value, BotCommandPropertyType commandType, Type propertyType)
{
return type switch
object convertedValue = commandType switch
{
BotCommandPropertyType.Time => this.ToTimeSpan(value),
BotCommandPropertyType.Number => int.Parse(value),
Expand All @@ -30,6 +30,10 @@ public object ConvertType(string value, BotCommandPropertyType type)
BotCommandPropertyType.ChannelMention => ulong.Parse(_exMention.Match(value).Value),
_ => value
};

var underlyingType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;
var result = Convert.ChangeType(convertedValue, underlyingType);
return result;
}

private TimeSpan ToTimeSpan(string value)
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Devscord.DiscordFramework.Commands.Responses;
using Devscord.DiscordFramework.Services;
using Moq;
using System;
using System.Threading.Tasks;

namespace Watchman.Discord.UnitTests.TestObjectFactories
{
// TODO: Use this anywhere it's needed.
internal class MessagesServiceMockWithResponsesFactory
{
public Mock<IMessagesService> Create(Mock<IResponsesService> responsesServiceMock)
{
var messagesServiceMock = new Mock<IMessagesService>();
messagesServiceMock.Setup(x => x.SendResponse(It.IsAny<Func<IResponsesService, string>>()))
.Callback<Func<IResponsesService, string>>(x => x.Invoke(responsesServiceMock.Object))
.Returns(Task.CompletedTask);

return messagesServiceMock;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Text;
using System.Threading.Tasks;

namespace Watchman.Discord.Areas.Configurations.IBotCommands
namespace Watchman.Discord.Areas.Configurations.BotCommands
{
public class ConfigurationsCommand : IBotCommand
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Devscord.DiscordFramework.Commands;
using Devscord.DiscordFramework.Commands.PropertyAttributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Watchman.Discord.Areas.Configurations.BotCommands
{
public class RemoveConfigurationCommand : IBotCommand
{
[SingleWord]
public string Name { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Devscord.DiscordFramework.Commands;
using Devscord.DiscordFramework.Commands.PropertyAttributes;
using System;
using System.Collections.Generic;

namespace Watchman.Discord.Areas.Configurations.BotCommands
{
// TODO: add option for list of each type not only string
public class SetConfigurationCommand : IBotCommand
{
[SingleWord]
public string Name { get; set; }

[Optional]
[Text]
public string TextValue { get; set; }

[Optional]
[Number]
public double? NumberValue { get; set; }

[Optional]
[Time]
public TimeSpan? TimeValue { get; set; }

[Optional]
[UserMention]
public ulong? UserValue { get; set; }

[Optional]
[ChannelMention]
public ulong? ChannelValue { get; set; }

[Optional]
[Text]
public string BoolValue { get; set; }

[Optional]
[List]
public List<string> ListValue { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,94 @@
using System.Text;
using System.Threading.Tasks;
using Watchman.Cqrs;
using Watchman.Discord.Areas.Configurations.IBotCommands;
using Watchman.Discord.Areas.Configurations.BotCommands;
using Watchman.DomainModel.Configuration;
using Watchman.DomainModel.Configuration.Queries;
using Watchman.DomainModel.Configuration.Services;
using Watchman.Discord.ResponsesManagers;
using Devscord.DiscordFramework.Commons.Exceptions;
using Watchman.Discord.Areas.Configurations.Services;
using Watchman.DomainModel.Responses;

namespace Watchman.Discord.Areas.Configurations.Controllers
{
public class ConfigurationsController : IController
{
private readonly IMessagesServiceFactory messagesServiceFactory;
private readonly IConfigurationService configurationService;
private readonly IMessagesServiceFactory _messagesServiceFactory;
private readonly IConfigurationService _configurationService;
private readonly IConfigurationMapperService _configurationMapperService;
private readonly IConfigurationValueSetter _configurationValueSetter;

public ConfigurationsController(IQueryBus queryBus, IMessagesServiceFactory messagesServiceFactory, IConfigurationService configurationService)
public ConfigurationsController(IMessagesServiceFactory messagesServiceFactory, IConfigurationService configurationService, IConfigurationMapperService configurationMapperService, IConfigurationValueSetter configurationValueSetter)
{
this.messagesServiceFactory = messagesServiceFactory;
this.configurationService = configurationService;
this._messagesServiceFactory = messagesServiceFactory;
this._configurationService = configurationService;
this._configurationMapperService = configurationMapperService;
this._configurationValueSetter = configurationValueSetter;
}

//todo tests
public async Task GetConfigurations(ConfigurationsCommand command, Contexts contexts)
{
var configurations = this.configurationService.GetConfigurationItems(contexts.Server.Id);
var configurations = this._configurationService.GetConfigurationItems(contexts.Server.Id);
if(command.Group != null)
{
configurations = configurations.Where(x => x.Group.ToLower() == command.Group.ToLower());
}
var groupped = configurations.GroupBy(x => x.Group).OrderBy(x => x.Key);
var mapped = groupped.Select(x => new KeyValuePair<string, string>(x.Key, $"```\n{string.Join("\n", x.Select(item => item.Name))}```"));
//todo from responses
var messagesService = this.messagesServiceFactory.Create(contexts);
var messagesService = this._messagesServiceFactory.Create(contexts);
await messagesService.SendEmbedMessage("Konfiguracja", "Poniżej znajdziesz liste elementów konfiguracji", mapped);
}

public async Task SetCustomConfiguration(SetConfigurationCommand command, Contexts contexts)
{
var mappedConfiguration = this._configurationService.GetConfigurationItems(contexts.Server.Id)
.FirstOrDefault(item => item.Name.ToLowerInvariant() == command.Name.ToLowerInvariant());
var messageService = this._messagesServiceFactory.Create(contexts);

if (mappedConfiguration == null)
{
await messageService.SendResponse(x => x.ConfigurationItemNotFound(command.Name));
return;
}

var propertiesValues = command.GetType().GetProperties().Where(x => x.Name.EndsWith("Value")).Select(x => x.GetValue(command));
var countOfPropertiesWithValue = propertiesValues.Count(x => x != null);
if (countOfPropertiesWithValue > 1)
{
await messageService.SendResponse(x => x.TooManyValueArgumentsForSetConfiguration());
return;
}

var configurationItem = this._configurationMapperService.MapIntoBaseFormat(mappedConfiguration, contexts.Server.Id);
var configurationValueType = this._configurationService.GetConfigurationValueType(mappedConfiguration);
if (countOfPropertiesWithValue == 0)
{
await this._configurationValueSetter.SetDefaultValueForConfiguration(configurationItem, configurationValueType);
await messageService.SendResponse(x => x.ConfigurationValueHasBeenSetAsDefaultOfType(contexts, command.Name));
return;
}

await this._configurationValueSetter.SetConfigurationValueFromCommand(command, configurationItem, propertiesValues, configurationValueType);
await messageService.SendResponse(x => x.CustomConfigurationHasBeenSet(contexts, command.Name));
}

public async Task RemoveCustomConfiguration(RemoveConfigurationCommand command, Contexts contexts)
{
var mappedConfiguration = this._configurationService.GetConfigurationItems(contexts.Server.Id)
.FirstOrDefault(item => item.Name.ToLowerInvariant() == command.Name.ToLowerInvariant());
var messageService = this._messagesServiceFactory.Create(contexts);

if (mappedConfiguration == null || mappedConfiguration.ServerId == Response.DEFAULT_SERVER_ID)
{
await messageService.SendResponse(x => x.ServerDoesntHaveCustomValueForConfiguration(contexts, command.Name));
return;
}

await this._configurationService.RemoveCustomConfiguration(mappedConfiguration);
await messageService.SendResponse(x => x.CustomConfigurationHasBeenRemoved(contexts, command.Name));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using Devscord.DiscordFramework.Commons.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Watchman.Discord.Areas.Configurations.BotCommands;
using Watchman.DomainModel.Configuration;
using Watchman.DomainModel.Configuration.Services;

namespace Watchman.Discord.Areas.Configurations.Services
{
public interface IConfigurationValueSetter
{
Task SetDefaultValueForConfiguration(ConfigurationItem configurationItem, Type valueType);
Task SetConfigurationValueFromCommand(SetConfigurationCommand command, ConfigurationItem configurationItem, IEnumerable<object> propertiesValues, Type configurationValueType);
}

// TODO: Add tests
public class ConfigurationValueSetter : IConfigurationValueSetter
{
private readonly IConfigurationService _configurationService;

public ConfigurationValueSetter(IConfigurationService configurationService)
{
_configurationService = configurationService;
}

public async Task SetDefaultValueForConfiguration(ConfigurationItem configurationItem, Type valueType)
{
var defaultTypeValue = valueType.IsValueType ? Activator.CreateInstance(valueType) : null;
await this.SetNewConfiguration(configurationItem, defaultTypeValue);
}

public async Task SetConfigurationValueFromCommand(SetConfigurationCommand command, ConfigurationItem configurationItem, IEnumerable<object> propertiesValues, Type configurationValueType)
{
var valueToSet = command switch
{
SetConfigurationCommand com when com.NumberValue != null
=> this.GetNumberValue(command.NumberValue, configurationValueType),

SetConfigurationCommand com when com.BoolValue != null
=> this.GetBoolValue(command.BoolValue, configurationValueType),

_ => this.GetCustomValue(propertiesValues, configurationValueType)
};
await this.SetNewConfiguration(configurationItem, valueToSet);
}

private object GetNumberValue(double? numberValue, Type configurationValueType)
{
const string defaultValueForNumberTypes = "0";
var underlyingValueType = this.GetUnderlyingType(configurationValueType);
var doesItemAcceptNumbers = underlyingValueType.IsValueType
? Activator.CreateInstance(underlyingValueType).ToString() == defaultValueForNumberTypes
: false;

if (!doesItemAcceptNumbers)
{
throw new InvalidArgumentsException();
}
return Convert.ChangeType(numberValue, configurationValueType);
}

private bool GetBoolValue(string valueInText, Type configurationValueType)
{
var isValueConvertibleToBool = bool.TryParse(valueInText, out var convertedValue);
var doesItemAcceptBool = configurationValueType == typeof(bool) || configurationValueType == typeof(bool?);

if (!isValueConvertibleToBool || !doesItemAcceptBool)
{
throw new InvalidArgumentsException();
}
return convertedValue;
}

private object GetCustomValue(IEnumerable<object> propertiesValues, Type configurationValueType)
{
var providedValue = propertiesValues.First(x => x != null);

var underlyingTypeOfProvidedValue = this.GetUnderlyingType(providedValue.GetType());
var underlyingConfigurationType = this.GetUnderlyingType(configurationValueType);

if (underlyingTypeOfProvidedValue != underlyingConfigurationType)
{
throw new InvalidArgumentsException();
}
return providedValue;
}

private Type GetUnderlyingType(Type type)
=> Nullable.GetUnderlyingType(type) ?? type;

private async Task SetNewConfiguration(ConfigurationItem configurationItem, object valueToSet)
{
configurationItem.SetValue(valueToSet);
await this._configurationService.SaveNewConfiguration(configurationItem);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Devscord.DiscordFramework.Commands.Responses;
using Devscord.DiscordFramework.Middlewares.Contexts;
using System.Collections.Generic;

namespace Watchman.Discord.ResponsesManagers
{
public static class ConfigurationsResponsesManager
{
public static string ConfigurationItemNotFound(this IResponsesService responsesService, string name)
{
return responsesService.ProcessResponse(nameof(ConfigurationItemNotFound),
new KeyValuePair<string, string>(nameof(name), name));
}

public static string TooManyValueArgumentsForSetConfiguration(this IResponsesService responsesService)
{
return responsesService.ProcessResponse(nameof(TooManyValueArgumentsForSetConfiguration));
}

public static string CustomConfigurationHasBeenSet(this IResponsesService responsesService, Contexts contexts, string name)
{
return responsesService.ProcessResponse(nameof(CustomConfigurationHasBeenSet), contexts,
new KeyValuePair<string, string>(nameof(name), name));
}

public static string ConfigurationValueHasBeenSetAsDefaultOfType(this IResponsesService responsesService, Contexts contexts, string name)
{
return responsesService.ProcessResponse(nameof(ConfigurationValueHasBeenSetAsDefaultOfType), contexts,
new KeyValuePair<string, string>(nameof(name), name));
}

public static string CustomConfigurationHasBeenRemoved(this IResponsesService responsesService, Contexts contexts, string name)
{
return responsesService.ProcessResponse(nameof(CustomConfigurationHasBeenRemoved), contexts,
new KeyValuePair<string, string>(nameof(name), name));
}

public static string ServerDoesntHaveCustomValueForConfiguration(this IResponsesService responsesService, Contexts contexts, string name)
{
return responsesService.ProcessResponse(nameof(ServerDoesntHaveCustomValueForConfiguration), contexts,
new KeyValuePair<string, string>(nameof(name), name));
}
}
}
Loading