Add project data
This commit is contained in:
91
Tabletop.Core/Calculators/Calculation.cs
Normal file
91
Tabletop.Core/Calculators/Calculation.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using Tabletop.Core.Constants;
|
||||
using Tabletop.Core.Models;
|
||||
using Tabletop.Core.Services;
|
||||
|
||||
namespace Tabletop.Core.Calculators
|
||||
{
|
||||
public class Calculation
|
||||
{
|
||||
public static async Task<int> ForceAsync(Unit unit)
|
||||
{
|
||||
double unitForce = unit.Defense * 25 + unit.Moving * 5;
|
||||
double primaryWeaponForce = 0;
|
||||
double secondaryWeaponForce = 0;
|
||||
|
||||
unit.PrimaryWeapon = AppdataService.Weapons.FirstOrDefault(x => x.WeaponId == unit.PrimaryWeaponId)?.DeepCopyByExpressionTree();
|
||||
unit.SecondaryWeapon = AppdataService.Weapons.FirstOrDefault(x => x.WeaponId == unit.SecondaryWeaponId)?.DeepCopyByExpressionTree();
|
||||
unit.FirstAbility = AppdataService.Abilities.FirstOrDefault(x => x.AbilityId == unit.FirstAbilityId)?.DeepCopyByExpressionTree();
|
||||
unit.SecondAbility = AppdataService.Abilities.FirstOrDefault(x => x.AbilityId == unit.SecondAbilityId)?.DeepCopyByExpressionTree();
|
||||
|
||||
if (unit.PrimaryWeapon != null)
|
||||
{
|
||||
primaryWeaponForce = unit.PrimaryWeapon.Attack * (unit.PrimaryWeapon.Quality + (unit.FirstAbility?.Quality ?? 0) + (unit.SecondAbility?.Quality ?? 0)) * (unit.PrimaryWeapon.Range / 10) * unit.PrimaryWeapon.Dices;
|
||||
}
|
||||
|
||||
if (unit.SecondaryWeapon != null)
|
||||
{
|
||||
secondaryWeaponForce = (unit.SecondaryWeapon.Attack * unit.SecondaryWeapon.Quality + (unit.FirstAbility?.Quality ?? 0) + (unit.SecondAbility?.Quality ?? 0)) * (unit.SecondaryWeapon.Range / 10) * unit.SecondaryWeapon.Dices;
|
||||
}
|
||||
|
||||
return await Task.FromResult(Convert.ToInt32(Math.Round((unitForce + primaryWeaponForce + secondaryWeaponForce) / 25) + (unit.FirstAbility?.Force ?? 0) + (unit.SecondAbility?.Force ?? 0)));
|
||||
}
|
||||
|
||||
public static Task<double> RandomNumberAsync()
|
||||
{
|
||||
Random random = new();
|
||||
double r = random.Next(1, 9);
|
||||
|
||||
return Task.FromResult(r);
|
||||
}
|
||||
|
||||
public static async Task<double> ProbabilityAsync(int attackerId, int defenderId, CoverTypes cover)
|
||||
{
|
||||
var (value0, value1) = await AttackValueTranslatorAsync(AppdataService.Weapons.FirstOrDefault(x => x.WeaponId == AppdataService.Units.FirstOrDefault(x => x.UnitId == attackerId)?.PrimaryWeaponId)?.Attack ?? 0, AppdataService.Units.FirstOrDefault(x => x.UnitId == defenderId)?.Defense ?? 0);
|
||||
double x = ((AppdataService.Weapons.FirstOrDefault(x => x.WeaponId == AppdataService.Units.FirstOrDefault(x => x.UnitId == attackerId)?.PrimaryWeaponId)?.Quality ?? 0) + ((AppdataService.Abilities.FirstOrDefault(x => x.AbilityId == AppdataService.Units.FirstOrDefault(x => x.UnitId == attackerId)?.FirstAbilityId)?.Quality ?? 0) + ((double)(AppdataService.Abilities.FirstOrDefault(x => x.AbilityId == AppdataService.Units.FirstOrDefault(x => x.UnitId == attackerId)?.SecondAbilityId)?.Quality ?? 0)))) / 8 * ((9 - (double)value0) / 8) * (AppdataService.Weapons.FirstOrDefault(x => x.WeaponId == AppdataService.Units.FirstOrDefault(x => x.UnitId == attackerId)?.PrimaryWeaponId)?.Dices ?? 1);
|
||||
|
||||
if (AppdataService.Weapons.FirstOrDefault(x => x.WeaponId == AppdataService.Units.FirstOrDefault(x => x.UnitId == attackerId)?.PrimaryWeaponId) == AppdataService.Weapons.FirstOrDefault(x => x.WeaponId == AppdataService.Units.FirstOrDefault(x => x.UnitId == attackerId)?.SecondaryWeaponId))
|
||||
{
|
||||
x *= 2;
|
||||
}
|
||||
|
||||
if (value1 != 0)
|
||||
{
|
||||
x *= (9 - (double)value1) / 8;
|
||||
}
|
||||
|
||||
if (Convert.ToInt32(cover) == 1)
|
||||
{
|
||||
x *= 0.75;
|
||||
}
|
||||
else if (Convert.ToInt32(cover) == 2)
|
||||
{
|
||||
x *= 0.625;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
public static Task<(int, int)> AttackValueTranslatorAsync(int attacker, int defender)
|
||||
{
|
||||
int x = 5;
|
||||
|
||||
if (attacker > defender)
|
||||
{
|
||||
x -= attacker - defender;
|
||||
}
|
||||
else if (attacker < defender)
|
||||
{
|
||||
x += defender - attacker;
|
||||
}
|
||||
if (x > 8)
|
||||
{
|
||||
return Task.FromResult((8, x - 6));
|
||||
}
|
||||
if (x < 2)
|
||||
{
|
||||
x = 2;
|
||||
}
|
||||
return Task.FromResult((x, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Tabletop.Core/Constants/CoverTypes.cs
Normal file
9
Tabletop.Core/Constants/CoverTypes.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Tabletop.Core.Constants
|
||||
{
|
||||
public enum CoverTypes
|
||||
{
|
||||
None = 0,
|
||||
Light = 1,
|
||||
Heavy = 2
|
||||
}
|
||||
}
|
||||
17
Tabletop.Core/Constants/PlayerColors.cs
Normal file
17
Tabletop.Core/Constants/PlayerColors.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Tabletop.Core.Constants
|
||||
{
|
||||
public static class PlayerColors
|
||||
{
|
||||
public static readonly List<string> Colors =
|
||||
[
|
||||
"#D32F2F", // Rot
|
||||
"#1976D2", // Blau
|
||||
"#388E3C", // Grün
|
||||
"#FBC02D", // Gelb
|
||||
"#F57C00", // Orange
|
||||
"#7B1FA2", // Violett
|
||||
"#00ACC1", // Türkis
|
||||
"#E91E63" // Magenta
|
||||
];
|
||||
}
|
||||
}
|
||||
30
Tabletop.Core/Constants/Roles.cs
Normal file
30
Tabletop.Core/Constants/Roles.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace Tabletop.Core.Constants
|
||||
{
|
||||
public static class Roles
|
||||
{
|
||||
public const string ADD_USERS = "ADD_USERS";
|
||||
public const string ADD_UNITS = "ADD_UNITS";
|
||||
public const string ADD_ABILITIES = "ADD_ABILITIES";
|
||||
public const string ADD_WEAPONS = "ADD_WEAPONS";
|
||||
public const string ADD_FRACTIONS = "ADD_FRACTIONS";
|
||||
public const string ADD_GAMEMODES = "ADD_GAMEMODES";
|
||||
public const string VIEW_USERS = "VIEW_USERS";
|
||||
public const string VIEW_UNITS = "VIEW_UNITS";
|
||||
public const string VIEW_ABILITIES = "VIEW_ABILITIES";
|
||||
public const string VIEW_WEAPONS = "VIEW_WEAPONS";
|
||||
public const string VIEW_FRACTIONS = "VIEW_FRACTIONS";
|
||||
public const string VIEW_GAMEMODES = "VIEW_GAMEMODES";
|
||||
public const string EDIT_USERS = "EDIT_USERS";
|
||||
public const string EDIT_UNITS = "EDIT_UNITS";
|
||||
public const string EDIT_ABILITIES = "EDIT_ABILITIES";
|
||||
public const string EDIT_WEAPONS = "EDIT_WEAPONS";
|
||||
public const string EDIT_FRACTIONS = "EDIT_FRACTIONS";
|
||||
public const string EDIT_GAMEMODES = "EDIT_GAMEMODES";
|
||||
public const string DELETE_USERS = "DELETE_USERS";
|
||||
public const string DELETE_UNITS = "DELETE_UNITS";
|
||||
public const string DELETE_ABILITIES = "DELETE_ABILITIES";
|
||||
public const string DELETE_WEAPONS = "DELETE_WEAPONS";
|
||||
public const string DELETE_FRACTIONS = "DELETE_FRACTIONS";
|
||||
public const string DELETE_GAMEMODES = "DELETE_GAMEMODES";
|
||||
}
|
||||
}
|
||||
774
Tabletop.Core/DeepCopy.cs
Normal file
774
Tabletop.Core/DeepCopy.cs
Normal file
@@ -0,0 +1,774 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
#nullable disable
|
||||
|
||||
namespace Tabletop.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Superfast deep copier class, which uses Expression trees.
|
||||
/// </summary>
|
||||
public static class DeepCopyByExpressionTrees
|
||||
{
|
||||
private static readonly object _isStructTypeToDeepCopyDictionaryLocker = new();
|
||||
private static Dictionary<Type, bool> _isStructTypeToDeepCopyDictionary = [];
|
||||
|
||||
private static readonly object _compiledCopyFunctionsDictionaryLocker = new();
|
||||
private static Dictionary<Type, Func<object, Dictionary<object, object>, object>> _compiledCopyFunctionsDictionary =
|
||||
[];
|
||||
|
||||
private static readonly Type _objectType = typeof(object);
|
||||
private static readonly Type _objectDictionaryType = typeof(Dictionary<object, object>);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep copy of an object.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Object type.</typeparam>
|
||||
/// <param name="original">Object to copy.</param>
|
||||
/// <param name="copiedReferencesDict">Dictionary of already copied objects (Keys: original objects, Values: their copies).</param>
|
||||
/// <returns></returns>
|
||||
public static T DeepCopyByExpressionTree<T>(this T original, Dictionary<object, object> copiedReferencesDict = null)
|
||||
{
|
||||
return (T)DeepCopyByExpressionTreeObj(original, false, copiedReferencesDict ?? new Dictionary<object, object>(new ReferenceEqualityComparer()));
|
||||
}
|
||||
|
||||
private static object DeepCopyByExpressionTreeObj(object original, bool forceDeepCopy, Dictionary<object, object> copiedReferencesDict)
|
||||
{
|
||||
if (original == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var type = original.GetType();
|
||||
|
||||
if (IsDelegate(type))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!forceDeepCopy && !IsTypeToDeepCopy(type))
|
||||
{
|
||||
return original;
|
||||
}
|
||||
|
||||
|
||||
if (copiedReferencesDict.TryGetValue(original, out object alreadyCopiedObject))
|
||||
{
|
||||
return alreadyCopiedObject;
|
||||
}
|
||||
|
||||
if (type == _objectType)
|
||||
{
|
||||
return new object();
|
||||
}
|
||||
|
||||
var compiledCopyFunction = GetOrCreateCompiledLambdaCopyFunction(type);
|
||||
|
||||
object copy = compiledCopyFunction(original, copiedReferencesDict);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static Func<object, Dictionary<object, object>, object> GetOrCreateCompiledLambdaCopyFunction(Type type)
|
||||
{
|
||||
// The following structure ensures that multiple threads can use the dictionary
|
||||
// even while dictionary is locked and being updated by other thread.
|
||||
// That is why we do not modify the old dictionary instance but
|
||||
// we replace it with a new instance everytime.
|
||||
|
||||
|
||||
if (!_compiledCopyFunctionsDictionary.TryGetValue(type, out Func<object, Dictionary<object, object>, object> compiledCopyFunction))
|
||||
{
|
||||
lock (_compiledCopyFunctionsDictionaryLocker)
|
||||
{
|
||||
if (!_compiledCopyFunctionsDictionary.TryGetValue(type, out compiledCopyFunction))
|
||||
{
|
||||
var uncompiledCopyFunction = CreateCompiledLambdaCopyFunctionForType(type);
|
||||
|
||||
compiledCopyFunction = uncompiledCopyFunction.Compile();
|
||||
|
||||
var dictionaryCopy = _compiledCopyFunctionsDictionary.ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
|
||||
dictionaryCopy.Add(type, compiledCopyFunction);
|
||||
|
||||
_compiledCopyFunctionsDictionary = dictionaryCopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return compiledCopyFunction;
|
||||
}
|
||||
|
||||
private static Expression<Func<object, Dictionary<object, object>, object>> CreateCompiledLambdaCopyFunctionForType(Type type)
|
||||
{
|
||||
|
||||
///// INITIALIZATION OF EXPRESSIONS AND VARIABLES
|
||||
|
||||
InitializeExpressions(type,
|
||||
out ParameterExpression inputParameter,
|
||||
out ParameterExpression inputDictionary,
|
||||
out ParameterExpression outputVariable,
|
||||
out ParameterExpression boxingVariable,
|
||||
out LabelTarget endLabel,
|
||||
out List<ParameterExpression> variables,
|
||||
out List<Expression> expressions);
|
||||
|
||||
///// RETURN NULL IF ORIGINAL IS NULL
|
||||
|
||||
IfNullThenReturnNullExpression(inputParameter, endLabel, expressions);
|
||||
|
||||
///// MEMBERWISE CLONE ORIGINAL OBJECT
|
||||
|
||||
MemberwiseCloneInputToOutputExpression(type, inputParameter, outputVariable, expressions);
|
||||
|
||||
///// STORE COPIED OBJECT TO REFERENCES DICTIONARY
|
||||
|
||||
if (IsClassOtherThanString(type))
|
||||
{
|
||||
StoreReferencesIntoDictionaryExpression(inputParameter, inputDictionary, outputVariable, expressions);
|
||||
}
|
||||
|
||||
///// COPY ALL NONVALUE OR NONPRIMITIVE FIELDS
|
||||
|
||||
FieldsCopyExpressions(type,
|
||||
inputParameter,
|
||||
inputDictionary,
|
||||
outputVariable,
|
||||
boxingVariable,
|
||||
expressions);
|
||||
|
||||
///// COPY ELEMENTS OF ARRAY
|
||||
|
||||
if (IsArray(type) && IsTypeToDeepCopy(type.GetElementType()))
|
||||
{
|
||||
CreateArrayCopyLoopExpression(type,
|
||||
inputParameter,
|
||||
inputDictionary,
|
||||
outputVariable,
|
||||
variables,
|
||||
expressions);
|
||||
}
|
||||
|
||||
///// COMBINE ALL EXPRESSIONS INTO LAMBDA FUNCTION
|
||||
|
||||
var lambda = CombineAllIntoLambdaFunctionExpression(inputParameter, inputDictionary, outputVariable, endLabel, variables, expressions);
|
||||
|
||||
return lambda;
|
||||
}
|
||||
|
||||
private static void InitializeExpressions(Type type,
|
||||
out ParameterExpression inputParameter,
|
||||
out ParameterExpression inputDictionary,
|
||||
out ParameterExpression outputVariable,
|
||||
out ParameterExpression boxingVariable,
|
||||
out LabelTarget endLabel,
|
||||
out List<ParameterExpression> variables,
|
||||
out List<Expression> expressions)
|
||||
{
|
||||
|
||||
inputParameter = Expression.Parameter(_objectType);
|
||||
|
||||
inputDictionary = Expression.Parameter(_objectDictionaryType);
|
||||
|
||||
outputVariable = Expression.Variable(type);
|
||||
|
||||
boxingVariable = Expression.Variable(_objectType);
|
||||
|
||||
endLabel = Expression.Label();
|
||||
|
||||
variables = [];
|
||||
|
||||
expressions = [];
|
||||
|
||||
variables.Add(outputVariable);
|
||||
variables.Add(boxingVariable);
|
||||
}
|
||||
|
||||
private static void IfNullThenReturnNullExpression(ParameterExpression inputParameter, LabelTarget endLabel, List<Expression> expressions)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// if (input == null)
|
||||
///// {
|
||||
///// return null;
|
||||
///// }
|
||||
|
||||
var ifNullThenReturnNullExpression =
|
||||
Expression.IfThen(
|
||||
Expression.Equal(
|
||||
inputParameter,
|
||||
Expression.Constant(null, _objectType)),
|
||||
Expression.Return(endLabel));
|
||||
|
||||
expressions.Add(ifNullThenReturnNullExpression);
|
||||
}
|
||||
|
||||
private static void MemberwiseCloneInputToOutputExpression(
|
||||
Type type,
|
||||
ParameterExpression inputParameter,
|
||||
ParameterExpression outputVariable,
|
||||
List<Expression> expressions)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// var output = (<type>)input.MemberwiseClone();
|
||||
|
||||
var memberwiseCloneMethod = _objectType.GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
var memberwiseCloneInputExpression =
|
||||
Expression.Assign(
|
||||
outputVariable,
|
||||
Expression.Convert(
|
||||
Expression.Call(
|
||||
inputParameter,
|
||||
memberwiseCloneMethod),
|
||||
type));
|
||||
|
||||
expressions.Add(memberwiseCloneInputExpression);
|
||||
}
|
||||
|
||||
private static void StoreReferencesIntoDictionaryExpression(ParameterExpression inputParameter,
|
||||
ParameterExpression inputDictionary,
|
||||
ParameterExpression outputVariable,
|
||||
List<Expression> expressions)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// inputDictionary[(Object)input] = (Object)output;
|
||||
|
||||
var storeReferencesExpression =
|
||||
Expression.Assign(
|
||||
Expression.Property(
|
||||
inputDictionary,
|
||||
_objectDictionaryType.GetProperty("Item"),
|
||||
inputParameter),
|
||||
Expression.Convert(outputVariable, _objectType));
|
||||
|
||||
expressions.Add(storeReferencesExpression);
|
||||
}
|
||||
|
||||
private static Expression<Func<object, Dictionary<object, object>, object>> CombineAllIntoLambdaFunctionExpression(
|
||||
ParameterExpression inputParameter,
|
||||
ParameterExpression inputDictionary,
|
||||
ParameterExpression outputVariable,
|
||||
LabelTarget endLabel,
|
||||
List<ParameterExpression> variables,
|
||||
List<Expression> expressions)
|
||||
{
|
||||
expressions.Add(Expression.Label(endLabel));
|
||||
|
||||
expressions.Add(Expression.Convert(outputVariable, _objectType));
|
||||
|
||||
var finalBody = Expression.Block(variables, expressions);
|
||||
|
||||
var lambda = Expression.Lambda<Func<object, Dictionary<object, object>, object>>(finalBody, inputParameter, inputDictionary);
|
||||
|
||||
return lambda;
|
||||
}
|
||||
|
||||
private static void CreateArrayCopyLoopExpression(Type type,
|
||||
ParameterExpression inputParameter,
|
||||
ParameterExpression inputDictionary,
|
||||
ParameterExpression outputVariable,
|
||||
List<ParameterExpression> variables,
|
||||
List<Expression> expressions)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// int i1, i2, ..., in;
|
||||
/////
|
||||
///// int length1 = inputarray.GetLength(0);
|
||||
///// i1 = 0;
|
||||
///// while (true)
|
||||
///// {
|
||||
///// if (i1 >= length1)
|
||||
///// {
|
||||
///// goto ENDLABELFORLOOP1;
|
||||
///// }
|
||||
///// int length2 = inputarray.GetLength(1);
|
||||
///// i2 = 0;
|
||||
///// while (true)
|
||||
///// {
|
||||
///// if (i2 >= length2)
|
||||
///// {
|
||||
///// goto ENDLABELFORLOOP2;
|
||||
///// }
|
||||
///// ...
|
||||
///// ...
|
||||
///// ...
|
||||
///// int lengthn = inputarray.GetLength(n);
|
||||
///// in = 0;
|
||||
///// while (true)
|
||||
///// {
|
||||
///// if (in >= lengthn)
|
||||
///// {
|
||||
///// goto ENDLABELFORLOOPn;
|
||||
///// }
|
||||
///// outputarray[i1, i2, ..., in]
|
||||
///// = (<elementType>)DeepCopyByExpressionTreeObj(
|
||||
///// (Object)inputarray[i1, i2, ..., in])
|
||||
///// in++;
|
||||
///// }
|
||||
///// ENDLABELFORLOOPn:
|
||||
///// ...
|
||||
///// ...
|
||||
///// ...
|
||||
///// i2++;
|
||||
///// }
|
||||
///// ENDLABELFORLOOP2:
|
||||
///// i1++;
|
||||
///// }
|
||||
///// ENDLABELFORLOOP1:
|
||||
|
||||
var rank = type.GetArrayRank();
|
||||
|
||||
var indices = GenerateIndices(rank);
|
||||
|
||||
variables.AddRange(indices);
|
||||
|
||||
var elementType = type.GetElementType();
|
||||
|
||||
var assignExpression = ArrayFieldToArrayFieldAssignExpression(inputParameter, inputDictionary, outputVariable, elementType, type, indices);
|
||||
|
||||
Expression forExpression = assignExpression;
|
||||
|
||||
for (int dimension = 0; dimension < rank; dimension++)
|
||||
{
|
||||
var indexVariable = indices[dimension];
|
||||
|
||||
forExpression = LoopIntoLoopExpression(inputParameter, indexVariable, forExpression, dimension);
|
||||
}
|
||||
|
||||
expressions.Add(forExpression);
|
||||
}
|
||||
|
||||
private static List<ParameterExpression> GenerateIndices(int arrayRank)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// int i1, i2, ..., in;
|
||||
|
||||
var indices = new List<ParameterExpression>();
|
||||
|
||||
for (int i = 0; i < arrayRank; i++)
|
||||
{
|
||||
var indexVariable = Expression.Variable(typeof(int));
|
||||
|
||||
indices.Add(indexVariable);
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
private static BinaryExpression ArrayFieldToArrayFieldAssignExpression(
|
||||
ParameterExpression inputParameter,
|
||||
ParameterExpression inputDictionary,
|
||||
ParameterExpression outputVariable,
|
||||
Type elementType,
|
||||
Type arrayType,
|
||||
List<ParameterExpression> indices)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// outputarray[i1, i2, ..., in]
|
||||
///// = (<elementType>)DeepCopyByExpressionTreeObj(
|
||||
///// (Object)inputarray[i1, i2, ..., in]);
|
||||
|
||||
var indexTo = Expression.ArrayAccess(outputVariable, indices);
|
||||
|
||||
var indexFrom = Expression.ArrayIndex(Expression.Convert(inputParameter, arrayType), indices);
|
||||
|
||||
var forceDeepCopy = elementType != _objectType;
|
||||
|
||||
var rightSide =
|
||||
Expression.Convert(
|
||||
Expression.Call(
|
||||
_deepCopyByExpressionTreeObjMethod,
|
||||
Expression.Convert(indexFrom, _objectType),
|
||||
Expression.Constant(forceDeepCopy, typeof(bool)),
|
||||
inputDictionary),
|
||||
elementType);
|
||||
|
||||
var assignExpression = Expression.Assign(indexTo, rightSide);
|
||||
|
||||
return assignExpression;
|
||||
}
|
||||
|
||||
private static BlockExpression LoopIntoLoopExpression(
|
||||
ParameterExpression inputParameter,
|
||||
ParameterExpression indexVariable,
|
||||
Expression loopToEncapsulate,
|
||||
int dimension)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// int length = inputarray.GetLength(dimension);
|
||||
///// i = 0;
|
||||
///// while (true)
|
||||
///// {
|
||||
///// if (i >= length)
|
||||
///// {
|
||||
///// goto ENDLABELFORLOOP;
|
||||
///// }
|
||||
///// loopToEncapsulate;
|
||||
///// i++;
|
||||
///// }
|
||||
///// ENDLABELFORLOOP:
|
||||
|
||||
var lengthVariable = Expression.Variable(typeof(int));
|
||||
|
||||
var endLabelForThisLoop = Expression.Label();
|
||||
|
||||
var newLoop =
|
||||
Expression.Loop(
|
||||
Expression.Block(
|
||||
[],
|
||||
Expression.IfThen(
|
||||
Expression.GreaterThanOrEqual(indexVariable, lengthVariable),
|
||||
Expression.Break(endLabelForThisLoop)),
|
||||
loopToEncapsulate,
|
||||
Expression.PostIncrementAssign(indexVariable)),
|
||||
endLabelForThisLoop);
|
||||
|
||||
var lengthAssignment = GetLengthForDimensionExpression(lengthVariable, inputParameter, dimension);
|
||||
|
||||
var indexAssignment = Expression.Assign(indexVariable, Expression.Constant(0));
|
||||
|
||||
return Expression.Block(
|
||||
[lengthVariable],
|
||||
lengthAssignment,
|
||||
indexAssignment,
|
||||
newLoop);
|
||||
}
|
||||
|
||||
private static BinaryExpression GetLengthForDimensionExpression(
|
||||
ParameterExpression lengthVariable,
|
||||
ParameterExpression inputParameter,
|
||||
int i)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// length = ((Array)input).GetLength(i);
|
||||
|
||||
var getLengthMethod = typeof(Array).GetMethod("GetLength", BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
var dimensionConstant = Expression.Constant(i);
|
||||
|
||||
return Expression.Assign(
|
||||
lengthVariable,
|
||||
Expression.Call(
|
||||
Expression.Convert(inputParameter, typeof(Array)),
|
||||
getLengthMethod,
|
||||
[dimensionConstant]));
|
||||
}
|
||||
|
||||
private static void FieldsCopyExpressions(Type type,
|
||||
ParameterExpression inputParameter,
|
||||
ParameterExpression inputDictionary,
|
||||
ParameterExpression outputVariable,
|
||||
ParameterExpression boxingVariable,
|
||||
List<Expression> expressions)
|
||||
{
|
||||
var fields = GetAllRelevantFields(type);
|
||||
|
||||
var readonlyFields = fields.Where(f => f.IsInitOnly).ToList();
|
||||
var writableFields = fields.Where(f => !f.IsInitOnly).ToList();
|
||||
|
||||
///// READONLY FIELDS COPY (with boxing)
|
||||
|
||||
bool shouldUseBoxing = readonlyFields.Count != 0;
|
||||
|
||||
if (shouldUseBoxing)
|
||||
{
|
||||
var boxingExpression = Expression.Assign(boxingVariable, Expression.Convert(outputVariable, _objectType));
|
||||
|
||||
expressions.Add(boxingExpression);
|
||||
}
|
||||
|
||||
foreach (var field in readonlyFields)
|
||||
{
|
||||
if (IsDelegate(field.FieldType))
|
||||
{
|
||||
ReadonlyFieldToNullExpression(field, boxingVariable, expressions);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadonlyFieldCopyExpression(type,
|
||||
field,
|
||||
inputParameter,
|
||||
inputDictionary,
|
||||
boxingVariable,
|
||||
expressions);
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldUseBoxing)
|
||||
{
|
||||
var unboxingExpression = Expression.Assign(outputVariable, Expression.Convert(boxingVariable, type));
|
||||
|
||||
expressions.Add(unboxingExpression);
|
||||
}
|
||||
|
||||
///// NOT-READONLY FIELDS COPY
|
||||
|
||||
foreach (var field in writableFields)
|
||||
{
|
||||
if (IsDelegate(field.FieldType))
|
||||
{
|
||||
WritableFieldToNullExpression(field, outputVariable, expressions);
|
||||
}
|
||||
else
|
||||
{
|
||||
WritableFieldCopyExpression(type,
|
||||
field,
|
||||
inputParameter,
|
||||
inputDictionary,
|
||||
outputVariable,
|
||||
expressions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static FieldInfo[] GetAllRelevantFields(Type type, bool forceAllFields = false)
|
||||
{
|
||||
var fieldsList = new List<FieldInfo>();
|
||||
|
||||
var typeCache = type;
|
||||
|
||||
while (typeCache != null)
|
||||
{
|
||||
fieldsList.AddRange(
|
||||
typeCache
|
||||
.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)
|
||||
.Where(field => forceAllFields || IsTypeToDeepCopy(field.FieldType)));
|
||||
|
||||
typeCache = typeCache.BaseType;
|
||||
}
|
||||
|
||||
return [.. fieldsList];
|
||||
}
|
||||
|
||||
private static FieldInfo[] GetAllFields(Type type)
|
||||
{
|
||||
return GetAllRelevantFields(type, forceAllFields: true);
|
||||
}
|
||||
|
||||
private static readonly Type _fieldInfoType = typeof(FieldInfo);
|
||||
private static readonly MethodInfo _setValueMethod = _fieldInfoType.GetMethod("SetValue", [_objectType, _objectType]);
|
||||
|
||||
private static void ReadonlyFieldToNullExpression(FieldInfo field, ParameterExpression boxingVariable, List<Expression> expressions)
|
||||
{
|
||||
// This option must be implemented by Reflection because of the following:
|
||||
// https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/2727812-allow-expression-assign-to-set-readonly-struct-f
|
||||
|
||||
///// Intended code:
|
||||
/////
|
||||
///// fieldInfo.SetValue(boxing, <fieldtype>null);
|
||||
|
||||
var fieldToNullExpression =
|
||||
Expression.Call(
|
||||
Expression.Constant(field),
|
||||
_setValueMethod,
|
||||
boxingVariable,
|
||||
Expression.Constant(null, field.FieldType));
|
||||
|
||||
expressions.Add(fieldToNullExpression);
|
||||
}
|
||||
|
||||
private static readonly Type _thisType = typeof(DeepCopyByExpressionTrees);
|
||||
private static readonly MethodInfo _deepCopyByExpressionTreeObjMethod = _thisType.GetMethod("DeepCopyByExpressionTreeObj", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
private static void ReadonlyFieldCopyExpression(Type type,
|
||||
FieldInfo field,
|
||||
ParameterExpression inputParameter,
|
||||
ParameterExpression inputDictionary,
|
||||
ParameterExpression boxingVariable,
|
||||
List<Expression> expressions)
|
||||
{
|
||||
// This option must be implemented by Reflection (SetValueMethod) because of the following:
|
||||
// https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/2727812-allow-expression-assign-to-set-readonly-struct-f
|
||||
|
||||
///// Intended code:
|
||||
/////
|
||||
///// fieldInfo.SetValue(boxing, DeepCopyByExpressionTreeObj((Object)((<type>)input).<field>))
|
||||
|
||||
var fieldFrom = Expression.Field(Expression.Convert(inputParameter, type), field);
|
||||
|
||||
var forceDeepCopy = field.FieldType != _objectType;
|
||||
|
||||
var fieldDeepCopyExpression =
|
||||
Expression.Call(
|
||||
Expression.Constant(field, _fieldInfoType),
|
||||
_setValueMethod,
|
||||
boxingVariable,
|
||||
Expression.Call(
|
||||
_deepCopyByExpressionTreeObjMethod,
|
||||
Expression.Convert(fieldFrom, _objectType),
|
||||
Expression.Constant(forceDeepCopy, typeof(bool)),
|
||||
inputDictionary));
|
||||
|
||||
expressions.Add(fieldDeepCopyExpression);
|
||||
}
|
||||
|
||||
private static void WritableFieldToNullExpression(FieldInfo field, ParameterExpression outputVariable, List<Expression> expressions)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// output.<field> = (<type>)null;
|
||||
|
||||
var fieldTo = Expression.Field(outputVariable, field);
|
||||
|
||||
var fieldToNullExpression =
|
||||
Expression.Assign(
|
||||
fieldTo,
|
||||
Expression.Constant(null, field.FieldType));
|
||||
|
||||
expressions.Add(fieldToNullExpression);
|
||||
}
|
||||
|
||||
private static void WritableFieldCopyExpression(Type type,
|
||||
FieldInfo field,
|
||||
ParameterExpression inputParameter,
|
||||
ParameterExpression inputDictionary,
|
||||
ParameterExpression outputVariable,
|
||||
List<Expression> expressions)
|
||||
{
|
||||
///// Intended code:
|
||||
/////
|
||||
///// output.<field> = (<fieldType>)DeepCopyByExpressionTreeObj((Object)((<type>)input).<field>);
|
||||
|
||||
var fieldFrom = Expression.Field(Expression.Convert(inputParameter, type), field);
|
||||
|
||||
var fieldType = field.FieldType;
|
||||
|
||||
var fieldTo = Expression.Field(outputVariable, field);
|
||||
|
||||
var forceDeepCopy = field.FieldType != _objectType;
|
||||
|
||||
var fieldDeepCopyExpression =
|
||||
Expression.Assign(
|
||||
fieldTo,
|
||||
Expression.Convert(
|
||||
Expression.Call(
|
||||
_deepCopyByExpressionTreeObjMethod,
|
||||
Expression.Convert(fieldFrom, _objectType),
|
||||
Expression.Constant(forceDeepCopy, typeof(bool)),
|
||||
inputDictionary),
|
||||
fieldType));
|
||||
|
||||
expressions.Add(fieldDeepCopyExpression);
|
||||
}
|
||||
|
||||
private static bool IsArray(Type type)
|
||||
{
|
||||
return type.IsArray;
|
||||
}
|
||||
|
||||
private static bool IsDelegate(Type type)
|
||||
{
|
||||
return typeof(Delegate).IsAssignableFrom(type);
|
||||
}
|
||||
|
||||
private static bool IsTypeToDeepCopy(Type type)
|
||||
{
|
||||
return IsClassOtherThanString(type)
|
||||
|| IsStructWhichNeedsDeepCopy(type);
|
||||
}
|
||||
|
||||
private static bool IsClassOtherThanString(Type type)
|
||||
{
|
||||
return !type.IsValueType && type != typeof(string);
|
||||
}
|
||||
|
||||
private static bool IsStructWhichNeedsDeepCopy(Type type)
|
||||
{
|
||||
// The following structure ensures that multiple threads can use the dictionary
|
||||
// even while dictionary is locked and being updated by other thread.
|
||||
// That is why we do not modify the old dictionary instance but
|
||||
// we replace it with a new instance everytime.
|
||||
|
||||
|
||||
if (!_isStructTypeToDeepCopyDictionary.TryGetValue(type, out bool isStructTypeToDeepCopy))
|
||||
{
|
||||
lock (_isStructTypeToDeepCopyDictionaryLocker)
|
||||
{
|
||||
if (!_isStructTypeToDeepCopyDictionary.TryGetValue(type, out isStructTypeToDeepCopy))
|
||||
{
|
||||
isStructTypeToDeepCopy = IsStructWhichNeedsDeepCopy_NoDictionaryUsed(type);
|
||||
|
||||
var newDictionary = _isStructTypeToDeepCopyDictionary.ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
|
||||
newDictionary[type] = isStructTypeToDeepCopy;
|
||||
|
||||
_isStructTypeToDeepCopyDictionary = newDictionary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isStructTypeToDeepCopy;
|
||||
}
|
||||
|
||||
private static bool IsStructWhichNeedsDeepCopy_NoDictionaryUsed(Type type)
|
||||
{
|
||||
return IsStructOtherThanBasicValueTypes(type)
|
||||
&& HasInItsHierarchyFieldsWithClasses(type);
|
||||
}
|
||||
|
||||
private static bool IsStructOtherThanBasicValueTypes(Type type)
|
||||
{
|
||||
return type.IsValueType
|
||||
&& !type.IsPrimitive
|
||||
&& !type.IsEnum
|
||||
&& type != typeof(decimal);
|
||||
}
|
||||
|
||||
private static bool HasInItsHierarchyFieldsWithClasses(Type type, HashSet<Type> alreadyCheckedTypes = null)
|
||||
{
|
||||
alreadyCheckedTypes ??= [];
|
||||
|
||||
alreadyCheckedTypes.Add(type);
|
||||
|
||||
var allFields = GetAllFields(type);
|
||||
|
||||
var allFieldTypes = allFields.Select(f => f.FieldType).Distinct().ToList();
|
||||
|
||||
var hasFieldsWithClasses = allFieldTypes.Any(IsClassOtherThanString);
|
||||
|
||||
if (hasFieldsWithClasses)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var notBasicStructsTypes = allFieldTypes.Where(IsStructOtherThanBasicValueTypes).ToList();
|
||||
|
||||
var typesToCheck = notBasicStructsTypes.Where(t => !alreadyCheckedTypes.Contains(t)).ToList();
|
||||
|
||||
foreach (var typeToCheck in typesToCheck)
|
||||
{
|
||||
if (HasInItsHierarchyFieldsWithClasses(typeToCheck, alreadyCheckedTypes))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public class ReferenceEqualityComparer : EqualityComparer<object>
|
||||
{
|
||||
public override bool Equals(object x, object y)
|
||||
{
|
||||
return ReferenceEquals(x, y);
|
||||
}
|
||||
|
||||
public override int GetHashCode(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Tabletop.Core/Extensions/StringExtensions.cs
Normal file
25
Tabletop.Core/Extensions/StringExtensions.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace Tabletop.Core.Extensions
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a random string
|
||||
/// </summary>
|
||||
/// <param name="length">The length of the random string</param>
|
||||
/// <returns></returns>
|
||||
public static string RandomString(int length)
|
||||
{
|
||||
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
var stringChars = new char[length];
|
||||
var random = new Random();
|
||||
|
||||
for (int i = 0; i < stringChars.Length; i++)
|
||||
{
|
||||
stringChars[i] = chars[random.Next(chars.Length)];
|
||||
}
|
||||
|
||||
var finalString = new string(stringChars);
|
||||
return finalString;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Tabletop.Core/Filters/AbilityFilter.cs
Normal file
9
Tabletop.Core/Filters/AbilityFilter.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Tabletop.Core.Filters.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Filters
|
||||
{
|
||||
public class AbilityFilter : PageFilterBase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
8
Tabletop.Core/Filters/Abstract/FilterBase.cs
Normal file
8
Tabletop.Core/Filters/Abstract/FilterBase.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Tabletop.Core.Filters.Abstract
|
||||
{
|
||||
public abstract class FilterBase
|
||||
{
|
||||
private string _searchPhrase = string.Empty;
|
||||
public string SearchPhrase { get => _searchPhrase; set => _searchPhrase = value?.ToUpper() ?? string.Empty; }
|
||||
}
|
||||
}
|
||||
11
Tabletop.Core/Filters/Abstract/PageFilterBase.cs
Normal file
11
Tabletop.Core/Filters/Abstract/PageFilterBase.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Tabletop.Core.Filters.Abstract
|
||||
{
|
||||
public abstract class PageFilterBase : FilterBase
|
||||
{
|
||||
private int _pageNumber = 1;
|
||||
private int _limit = 30;
|
||||
|
||||
public int PageNumber { get => _pageNumber; set => _pageNumber = value < 1 ? 1 : value; }
|
||||
public int Limit { get => _limit; set => _limit = value < 1 ? 1 : value; }
|
||||
}
|
||||
}
|
||||
9
Tabletop.Core/Filters/FractionFilter.cs
Normal file
9
Tabletop.Core/Filters/FractionFilter.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Tabletop.Core.Filters.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Filters
|
||||
{
|
||||
public class FractionFilter : PageFilterBase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
9
Tabletop.Core/Filters/GameFilter.cs
Normal file
9
Tabletop.Core/Filters/GameFilter.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Tabletop.Core.Filters.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Filters
|
||||
{
|
||||
public class GameFilter : PageFilterBase
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
}
|
||||
}
|
||||
9
Tabletop.Core/Filters/GamemodeFilter.cs
Normal file
9
Tabletop.Core/Filters/GamemodeFilter.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Tabletop.Core.Filters.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Filters
|
||||
{
|
||||
public class GamemodeFilter : PageFilterBase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
11
Tabletop.Core/Filters/TemplateFilter.cs
Normal file
11
Tabletop.Core/Filters/TemplateFilter.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Tabletop.Core.Filters.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Filters
|
||||
{
|
||||
public class TemplateFilter : PageFilterBase
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public int FractionId { get; set; }
|
||||
public int Force { get; set; }
|
||||
}
|
||||
}
|
||||
9
Tabletop.Core/Filters/UnitFilter.cs
Normal file
9
Tabletop.Core/Filters/UnitFilter.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Tabletop.Core.Filters.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Filters
|
||||
{
|
||||
public class UnitFilter : PageFilterBase
|
||||
{
|
||||
public int FractionId { get; set; }
|
||||
}
|
||||
}
|
||||
8
Tabletop.Core/Filters/UserFilter.cs
Normal file
8
Tabletop.Core/Filters/UserFilter.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Tabletop.Core.Filters.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Filters
|
||||
{
|
||||
public class UserFilter : PageFilterBase
|
||||
{
|
||||
}
|
||||
}
|
||||
9
Tabletop.Core/Filters/WeaponFilter.cs
Normal file
9
Tabletop.Core/Filters/WeaponFilter.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Tabletop.Core.Filters.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Filters
|
||||
{
|
||||
public class WeaponFilter : PageFilterBase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
13
Tabletop.Core/Interfaces/ILocalizationHelper.cs
Normal file
13
Tabletop.Core/Interfaces/ILocalizationHelper.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Tabletop.Core.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper interface to provide properties which can be used within the interface <see cref="ILocalizedDbModel{T}"/>
|
||||
/// </summary>
|
||||
public interface ILocalizationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the ISO 639-1 two letter code for the language
|
||||
/// </summary>
|
||||
string Code { get; set; }
|
||||
}
|
||||
}
|
||||
45
Tabletop.Core/Middlewares/ConnectionLogMiddleware.cs
Normal file
45
Tabletop.Core/Middlewares/ConnectionLogMiddleware.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using DbController.SqlServer;
|
||||
using DbController;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Tabletop.Core.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Tabletop.Core.Middlewares
|
||||
{
|
||||
public class ConnectionLogMiddleware(RequestDelegate next, IServiceProvider serviceProvider, ILogger<ConnectionLogMiddleware> logger)
|
||||
{
|
||||
private readonly RequestDelegate _next = next;
|
||||
private readonly IServiceProvider _serviceProvider = serviceProvider;
|
||||
private readonly ILogger<ConnectionLogMiddleware> _logger = logger;
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
// Erstelle ein ServiceScope, um Scoped Services zu verwenden
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var connectionLogService = scope.ServiceProvider.GetRequiredService<ConnectionLogService>();
|
||||
|
||||
// Erstelle das ConnectionLog
|
||||
var connectionLog = await connectionLogService.GetConnectionLogAsync(context);
|
||||
|
||||
if (connectionLog.IpAddress is not ("84.119.112.185" or "127.0.0.1" or "::1"))
|
||||
{
|
||||
// Verwende den dbController zur Speicherung des Logs in der DB
|
||||
using IDbController dbController = new SqlController(AppdataService.ConnectionString);
|
||||
await ConnectionLogService.CreateAsync(connectionLog, dbController);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Fehlerbehandlung und Logging
|
||||
_logger.LogError($"Fehler beim Erstellen des ConnectionLogs: {ex.Message}", ex);
|
||||
}
|
||||
|
||||
// Weiter zum nächsten Middleware in der Pipeline
|
||||
await _next(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Tabletop.Core/Models/Ability.cs
Normal file
64
Tabletop.Core/Models/Ability.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Ability : LocalizationModelBase<AbilityDescription>, IDbModel<int?>
|
||||
{
|
||||
[CompareField("ability_id")]
|
||||
public int AbilityId { get; set; }
|
||||
|
||||
[CompareField("quality")]
|
||||
public int Quality { get; set; }
|
||||
[CompareField("force")]
|
||||
public int Force { get; set; }
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return AbilityId > 0 ? AbilityId : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Dictionary<string, object?>> GetLocalizedParameters()
|
||||
{
|
||||
foreach (var description in Description)
|
||||
{
|
||||
yield return new Dictionary<string, object?>
|
||||
{
|
||||
{ "ABILITY_ID", AbilityId },
|
||||
{ "NAME", description.Name },
|
||||
{ "DESCRIPTION", description.Description },
|
||||
{ "MECHANIC", description.Mechanic }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "ABILITY_ID", AbilityId },
|
||||
{ "QUALITY", Quality },
|
||||
{ "FORCE", Force }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class AbilityDescription : ILocalizationHelper
|
||||
{
|
||||
[CompareField("ability_id")]
|
||||
public int AbilityId { get; set; }
|
||||
|
||||
[CompareField("code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("mechanic")]
|
||||
public string Mechanic { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
24
Tabletop.Core/Models/Abstract/ArmyBase.cs
Normal file
24
Tabletop.Core/Models/Abstract/ArmyBase.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models.Abstract
|
||||
{
|
||||
public abstract class ArmyBase
|
||||
{
|
||||
[CompareField("fraction_id")]
|
||||
public int FractionId { get; set; }
|
||||
[CompareField("used_force")]
|
||||
public int UsedForce { get; set; }
|
||||
|
||||
public List<Unit> Units { get; set; } = [];
|
||||
public int TotalUnits { get; set; }
|
||||
|
||||
public virtual Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "FRACTION_ID", FractionId },
|
||||
{ "USED_FORCE", UsedForce }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Tabletop.Core/Models/Abstract/LocalizationModelBase.cs
Normal file
15
Tabletop.Core/Models/Abstract/LocalizationModelBase.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Globalization;
|
||||
using Tabletop.Core.Interfaces;
|
||||
|
||||
namespace Tabletop.Core.Models.Abstract
|
||||
{
|
||||
public abstract class LocalizationModelBase<T> where T : ILocalizationHelper
|
||||
{
|
||||
public List<T> Description { get; set; } = [];
|
||||
public T? GetLocalization(CultureInfo culture)
|
||||
{
|
||||
var description = Description.FirstOrDefault(x => x.Code.Equals(culture.TwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase));
|
||||
return description;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Tabletop.Core/Models/Abstract/ZoneBase.cs
Normal file
27
Tabletop.Core/Models/Abstract/ZoneBase.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models.Abstract
|
||||
{
|
||||
public abstract class ZoneBase
|
||||
{
|
||||
[CompareField("x")]
|
||||
public string X { get; set; } = string.Empty;
|
||||
[CompareField("y")]
|
||||
public string Y { get; set; } = string.Empty;
|
||||
[CompareField("width")]
|
||||
public string Width { get; set; } = string.Empty;
|
||||
[CompareField("height")]
|
||||
public string Height { get; set; } = string.Empty;
|
||||
|
||||
public virtual Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "X", X },
|
||||
{ "Y", Y },
|
||||
{ "WIDTH", Width },
|
||||
{ "HEIGHT", Height }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Tabletop.Core/Models/Capture.cs
Normal file
36
Tabletop.Core/Models/Capture.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Capture
|
||||
{
|
||||
[CompareField("capture_id")]
|
||||
public int CaptureId { get; set; }
|
||||
[CompareField("move_id")]
|
||||
public int MoveId { get; set; }
|
||||
[CompareField("player_id")]
|
||||
public int PlayerId { get; set; }
|
||||
[CompareField("team_id")]
|
||||
public int TeamId { get; set; }
|
||||
[CompareField("capture_zone_nr")]
|
||||
public int CaptureZoneNr { get; set; }
|
||||
[CompareField("nr_of_turns")]
|
||||
public int NrOfTurns { get; set; }
|
||||
[CompareField("points_received")]
|
||||
public int PointsReceived { get; set; }
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "CAPTURE_ID", CaptureId },
|
||||
{ "MOVE_ID", MoveId },
|
||||
{ "PLAYER_ID", PlayerId },
|
||||
{ "TEAM_ID", TeamId },
|
||||
{ "CAPTURE_ZONE_NR", CaptureZoneNr },
|
||||
{ "NR_OF_TURNS", NrOfTurns },
|
||||
{ "POINTS_RECEIVED", PointsReceived }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Tabletop.Core/Models/CaptureZone.cs
Normal file
22
Tabletop.Core/Models/CaptureZone.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class CaptureZone : ZoneBase
|
||||
{
|
||||
[CompareField("capturezone_id")]
|
||||
public int CaptureZoneId { get; set; }
|
||||
[CompareField("points_per_round")]
|
||||
public int PointsPerRound { get; set; }
|
||||
|
||||
public override Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
var baseParams = base.GetParameters();
|
||||
baseParams["CAPTUREZONE_ID"] = CaptureZoneId;
|
||||
baseParams["POINTS_PER_ROUNDS"] = PointsPerRound;
|
||||
|
||||
return baseParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Tabletop.Core/Models/Class.cs
Normal file
57
Tabletop.Core/Models/Class.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Class : LocalizationModelBase<ClassDescription>
|
||||
{
|
||||
[CompareField("class_id")]
|
||||
public int ClassId { get; set; }
|
||||
|
||||
[CompareField("quantity")]
|
||||
public string Quantity { get; set; } = string.Empty;
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return ClassId > 0 ? ClassId : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Dictionary<string, object?>> GetLocalizedParameters()
|
||||
{
|
||||
foreach (var description in Description)
|
||||
{
|
||||
yield return new Dictionary<string, object?>
|
||||
{
|
||||
{ "CLASS_ID", ClassId },
|
||||
{ "NAME", description.Name },
|
||||
{ "DESCRIPTION", description.Description }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "CLASS_ID", ClassId },
|
||||
{ "QUANTITY", Quantity }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class ClassDescription : ILocalizationHelper
|
||||
{
|
||||
[CompareField("class_id")]
|
||||
public int ClassId { get; set; }
|
||||
|
||||
[CompareField("code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
63
Tabletop.Core/Models/ConnectionLog.cs
Normal file
63
Tabletop.Core/Models/ConnectionLog.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public enum DeviceType
|
||||
{
|
||||
Desktop,
|
||||
Tablet,
|
||||
Smartphone,
|
||||
Other
|
||||
}
|
||||
|
||||
public enum OperatingSystem
|
||||
{
|
||||
Windows,
|
||||
macOS,
|
||||
Linux,
|
||||
iOS,
|
||||
Android,
|
||||
Other
|
||||
}
|
||||
|
||||
public class ConnectionLog
|
||||
{
|
||||
[CompareField("ip_address")]
|
||||
public string IpAddress { get; set; } = string.Empty; // IP-Adresse des Besuchers
|
||||
[CompareField("connection_time")]
|
||||
public DateTime ConnectionTime { get; set; } // Zeitstempel des Zugriffs
|
||||
[CompareField("user_agent")]
|
||||
public string UserAgent { get; set; } = string.Empty; // User-Agent (Browser/OS)
|
||||
[CompareField("referrer")]
|
||||
public string Referrer { get; set; } = string.Empty; // Referrer (URL der vorherigen Seite)
|
||||
[CompareField("requested_url")]
|
||||
public string RequestedUrl { get; set; } = string.Empty; // Angeforderte URL
|
||||
[CompareField("geolocation")]
|
||||
public string? Geolocation { get; set; } = null; // Geografische Lage (optional, kann null sein)
|
||||
[CompareField("session_id")]
|
||||
public string SessionId { get; set; } = string.Empty; // Sitzungs-ID
|
||||
[CompareField("status_code")]
|
||||
public int StatusCode { get; set; } // HTTP-Statuscode der Antwort
|
||||
[CompareField("device_type")]
|
||||
public string DeviceType { get; set; } = string.Empty; // Gerätetyp (Desktop/Tablet/Smartphone)
|
||||
[CompareField("operating_system")]
|
||||
public string OperatingSystem { get; set; } = string.Empty; // Betriebssystem des Besuchers
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "IP_ADDRESS", IpAddress },
|
||||
{ "CONNECTION_TIME", ConnectionTime },
|
||||
{ "USER_AGENT", UserAgent },
|
||||
{ "REFERRER", Referrer },
|
||||
{ "REQUESTED_URL", RequestedUrl },
|
||||
{ "GEOLOCATION", Geolocation },
|
||||
{ "SESSION_ID", SessionId },
|
||||
{ "STATUS_CODE", StatusCode },
|
||||
{ "DEVICE_TYPE", DeviceType },
|
||||
{ "OPERATING_SYSTEM", OperatingSystem }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
49
Tabletop.Core/Models/Elimination.cs
Normal file
49
Tabletop.Core/Models/Elimination.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Elimination
|
||||
{
|
||||
[CompareField("elimination_id")]
|
||||
public int EliminationId { get; set; }
|
||||
[CompareField("move_id")]
|
||||
public int MoveId { get; set; }
|
||||
[CompareField("team_id")]
|
||||
public int TeamId { get; set; }
|
||||
[CompareField("atk_id")]
|
||||
public int AtkId { get; set; }
|
||||
[CompareField("atk_unit_id")]
|
||||
public int AtkUnitId { get; set; }
|
||||
[CompareField("atk_unit_nr")]
|
||||
public int AtkUnitNr { get; set; }
|
||||
[CompareField("def_id")]
|
||||
public int DefId { get; set; }
|
||||
[CompareField("def_unit_id")]
|
||||
public int DefUnitId { get; set; }
|
||||
[CompareField("def_unit_nr")]
|
||||
public int DefUnitNr { get; set; }
|
||||
[CompareField("elimination_nr")]
|
||||
public int EliminationNr { get; set; }
|
||||
[CompareField("ForcePointsEliminations")]
|
||||
public int ForcePointsEliminations { get; set; }
|
||||
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "ELIMINATION_ID", EliminationId },
|
||||
{ "MOVE_ID", MoveId },
|
||||
{ "TEAM_ID", TeamId },
|
||||
{ "ATK_ID", AtkId },
|
||||
{ "ATK_UNIT_ID", AtkUnitId },
|
||||
{ "ATK_UNIT_NR", AtkUnitNr },
|
||||
{ "DEF_ID", DefId },
|
||||
{ "DEF_UNIT_ID", DefUnitId },
|
||||
{ "DEF_UNIT_NR", DefUnitNr },
|
||||
{ "ELIMINATION_NR", EliminationNr },
|
||||
{ "FORCEPOINTSELIMINATIONS", ForcePointsEliminations }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Tabletop.Core/Models/Fraction.cs
Normal file
64
Tabletop.Core/Models/Fraction.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Fraction : LocalizationModelBase<FractionDescription>, IDbModel<int?>
|
||||
{
|
||||
[CompareField("fraction_id")]
|
||||
public int FractionId { get; set; }
|
||||
|
||||
[CompareField("image")]
|
||||
public byte[]? Image { get; set; }
|
||||
|
||||
public string ConvertedImage { get; set; } = string.Empty;
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return FractionId > 0 ? FractionId : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Dictionary<string, object?>> GetLocalizedParameters()
|
||||
{
|
||||
foreach (var description in Description)
|
||||
{
|
||||
yield return new Dictionary<string, object?>
|
||||
{
|
||||
{ "PERMISSION_ID", FractionId },
|
||||
{ "NAME", description.Name },
|
||||
{ "SHORT_NAME", description.ShortName },
|
||||
{ "DESCRIPTION", description.Description }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "FRACTION_ID", FractionId },
|
||||
{ "IMAGE", Image }
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class FractionDescription : ILocalizationHelper
|
||||
{
|
||||
[CompareField("fraction_id")]
|
||||
public int FractionId { get; set; }
|
||||
|
||||
[CompareField("code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("short_name")]
|
||||
public string ShortName { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
62
Tabletop.Core/Models/Game.cs
Normal file
62
Tabletop.Core/Models/Game.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Game : IDbModel<int?>
|
||||
{
|
||||
[CompareField("game_id")]
|
||||
public int GameId { get; set; }
|
||||
[CompareField("gamemode_id")]
|
||||
public int GamemodeId { get; set; }
|
||||
[CompareField("user_id")]
|
||||
public int UserId { get; set; }
|
||||
[CompareField("surface_id")]
|
||||
public int SurfaceId { get; set; }
|
||||
[CompareField("layout_id")]
|
||||
public int LayoutId { get; set; }
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
[CompareField("number_of_rounds")]
|
||||
public int? NumberOfRounds { get; set; }
|
||||
[CompareField("force")]
|
||||
public int Force { get; set; }
|
||||
[CompareField("number_of_teams")]
|
||||
public int NumberOfTeams { get; set; }
|
||||
[CompareField("number_of_players")]
|
||||
public int NumberOfPlayers { get; set; }
|
||||
[CompareField("date")]
|
||||
public DateTime Date { get; set; } = DateTime.Now;
|
||||
|
||||
public string Host { get; set; } = string.Empty;
|
||||
|
||||
public List<Player> Players { get; set; } = [];
|
||||
public List<Move> Rounds { get; set; } = [];
|
||||
public List<Capture> Captures { get; set; } = [];
|
||||
public List<Elimination> Elimination { get; set; } = [];
|
||||
|
||||
public string GUID { get; set; } = string.Empty;
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return GameId > 0 ? GameId : null;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "GAME_ID", GameId },
|
||||
{ "GAMEMODE_ID", GamemodeId },
|
||||
{ "USER_ID", UserId },
|
||||
{ "SURFACE_ID", SurfaceId },
|
||||
{ "LAYOUT_ID", LayoutId },
|
||||
{ "NAME", Name },
|
||||
{ "NUMBER_OF_ROUNDS", NumberOfRounds },
|
||||
{ "FORCE", Force },
|
||||
{ "NUMBER_OF_TEAMS", NumberOfTeams },
|
||||
{ "NUMBER_OF_PLAYERS", NumberOfPlayers },
|
||||
{ "DATE", Date }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
63
Tabletop.Core/Models/GameMode.cs
Normal file
63
Tabletop.Core/Models/GameMode.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Gamemode : LocalizationModelBase<GamemodeDescription>, IDbModel<int?>
|
||||
{
|
||||
[CompareField("gamemode_id")]
|
||||
public int GamemodeId { get; set; }
|
||||
|
||||
[CompareField("image")]
|
||||
public byte[]? Image { get; set; }
|
||||
|
||||
public string ConvertedImage { get; set; } = string.Empty;
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return GamemodeId > 0 ? GamemodeId : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Dictionary<string, object?>> GetLocalizedParameters()
|
||||
{
|
||||
foreach (var description in Description)
|
||||
{
|
||||
yield return new Dictionary<string, object?>
|
||||
{
|
||||
{ "PERMISSION_ID", GamemodeId },
|
||||
{ "NAME", description.Name },
|
||||
{ "DESCRIPTION", description.Description },
|
||||
{ "MECHANIC", description.Mechanic }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "GAMEMODE_ID", GamemodeId },
|
||||
{ "IMAGE", Image }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class GamemodeDescription : ILocalizationHelper
|
||||
{
|
||||
[CompareField("gamemode_id")]
|
||||
public int GamemodeId { get; set; }
|
||||
|
||||
[CompareField("code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("mechanic")]
|
||||
public string Mechanic { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
19
Tabletop.Core/Models/Geolocation.cs
Normal file
19
Tabletop.Core/Models/Geolocation.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Geolocation
|
||||
{
|
||||
[JsonProperty("country_name")]
|
||||
public string CountryName { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("city")]
|
||||
public string City { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("latitude")]
|
||||
public double Latitude { get; set; }
|
||||
|
||||
[JsonProperty("longitude")]
|
||||
public double Longitude { get; set; }
|
||||
}
|
||||
}
|
||||
64
Tabletop.Core/Models/Layout.cs
Normal file
64
Tabletop.Core/Models/Layout.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Layout : LocalizationModelBase<LayoutDescription>, IDbModel<int?>
|
||||
{
|
||||
[CompareField("layout_id")]
|
||||
public int LayoutId { get; set; }
|
||||
[CompareField("gamemode_id")]
|
||||
public int GamemodeId { get; set; }
|
||||
[CompareField("teams")]
|
||||
public int Teams { get; set; }
|
||||
[CompareField("width")]
|
||||
public string Width { get; set; } = string.Empty;
|
||||
[CompareField("height")]
|
||||
public string Height { get; set; } = string.Empty;
|
||||
|
||||
public List<SetupZone> SetupZones { get; set; } = [];
|
||||
public List<CaptureZone> CaptureZones { get; set; } = [];
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return LayoutId > 0 ? LayoutId : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Dictionary<string, object?>> GetLocalizedParameters()
|
||||
{
|
||||
foreach (var description in Description)
|
||||
{
|
||||
yield return new Dictionary<string, object?>
|
||||
{
|
||||
{ "LAYOUT_ID", LayoutId },
|
||||
{ "NAME", description.Name }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "LAYOUT_ID", LayoutId },
|
||||
{ "GAMEMODE_ID", GamemodeId },
|
||||
{ "TEAMS", Teams },
|
||||
{ "WIDTH", Width },
|
||||
{ "HEIGHT", Height }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class LayoutDescription : ILocalizationHelper
|
||||
{
|
||||
[CompareField("layout_id")]
|
||||
public int LayoutId { get; set; }
|
||||
|
||||
[CompareField("code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
36
Tabletop.Core/Models/Move.cs
Normal file
36
Tabletop.Core/Models/Move.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Move
|
||||
{
|
||||
[CompareField("move_id")]
|
||||
public int MoveId { get; set; }
|
||||
[CompareField("player_id")]
|
||||
public int PlayerId { get; set; }
|
||||
[CompareField("game_id")]
|
||||
public int GameId { get; set; }
|
||||
[CompareField("turn_nr")]
|
||||
public int TurnNr { get; set; }
|
||||
[CompareField("move_nr")]
|
||||
public int MoveNr { get; set; }
|
||||
[CompareField("start_move")]
|
||||
public DateTime StartMove { get; set; }
|
||||
[CompareField("end_move")]
|
||||
public DateTime EndMove { get; set; }
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "move_id", MoveId },
|
||||
{ "player_id", PlayerId },
|
||||
{ "game_id", GameId },
|
||||
{ "turn_nr", TurnNr },
|
||||
{ "move_nr", MoveNr },
|
||||
{ "start_move", StartMove },
|
||||
{ "end_move", EndMove }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Tabletop.Core/Models/Permission.cs
Normal file
57
Tabletop.Core/Models/Permission.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Permission : LocalizationModelBase<PermissionDescription>
|
||||
{
|
||||
[CompareField("permission_id")]
|
||||
public int PermissionId { get; set; }
|
||||
|
||||
[CompareField("identifier")]
|
||||
public string Identifier { get; set; } = string.Empty;
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return PermissionId > 0 ? PermissionId : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Dictionary<string, object?>> GetLocalizedParameters()
|
||||
{
|
||||
foreach (var description in Description)
|
||||
{
|
||||
yield return new Dictionary<string, object?>
|
||||
{
|
||||
{ "PERMISSION_ID", PermissionId },
|
||||
{ "NAME", description.Name },
|
||||
{ "DESCRIPTION", description.Description }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "PERMISSION_ID", PermissionId },
|
||||
{ "IDENTIFIER", Identifier }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class PermissionDescription : ILocalizationHelper
|
||||
{
|
||||
[CompareField("permission_id")]
|
||||
public int PermissionId { get; set; }
|
||||
|
||||
[CompareField("code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
58
Tabletop.Core/Models/Player.cs
Normal file
58
Tabletop.Core/Models/Player.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Player : ArmyBase
|
||||
{
|
||||
[CompareField("player_id")]
|
||||
public int PlayerId { get; set; }
|
||||
[CompareField("user_id")]
|
||||
public int UserId { get; set; }
|
||||
[CompareField("game_id")]
|
||||
public int GameId { get; set; }
|
||||
[CompareField("team")]
|
||||
public int Team { get; set; }
|
||||
[CompareField("color")]
|
||||
public string Color { get; set; } = string.Empty;
|
||||
[CompareField("points")]
|
||||
public int Points { get; set; }
|
||||
[CompareField("order_nr")]
|
||||
public int OrderNr { get; set; }
|
||||
[CompareField("start_zone")]
|
||||
public int StartZone { get; set; }
|
||||
[CompareField("number_of_eliminations")]
|
||||
public int NumberOfEliminations { get; set; }
|
||||
[CompareField("force_points_of_eliminations")]
|
||||
public int ForcePointsOfEliminations { get; set; }
|
||||
[CompareField("number_of_remaining_units")]
|
||||
public int NumberOfRemainingUnits { get; set; }
|
||||
[CompareField("own_force_points_left")]
|
||||
public int OwnForcePointsLeft { get; set; }
|
||||
|
||||
|
||||
public int AllowedForce { get; set; }
|
||||
public User User { get; set; } = new();
|
||||
|
||||
public string ConnectionId { get; set; } = string.Empty; // Verbindung zu SignalR
|
||||
public bool IsReady { get; set; }
|
||||
|
||||
public override Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
var baseParams = base.GetParameters();
|
||||
|
||||
baseParams["PLAYER_ID"] = PlayerId;
|
||||
baseParams["USER_ID"] = UserId;
|
||||
baseParams["GAME_ID"] = GameId;
|
||||
baseParams["TEAM"] = Team;
|
||||
baseParams["COLOR"] = Color;
|
||||
baseParams["ORDER_NR"] = OrderNr;
|
||||
baseParams["START_ZONE"] = StartZone;
|
||||
baseParams["NUMBER_OF_ELIMINATIONS"] = NumberOfEliminations;
|
||||
baseParams["FORCE_POINTS_OF_ELIMINATIONS"] = ForcePointsOfEliminations;
|
||||
baseParams["NUMBER_OF_REMAINING_UNITS"] = NumberOfRemainingUnits;
|
||||
baseParams["OWN_FORCE_POINTS_LEFT"] = OwnForcePointsLeft;
|
||||
return baseParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Tabletop.Core/Models/SetupZone.cs
Normal file
20
Tabletop.Core/Models/SetupZone.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class SetupZone : ZoneBase
|
||||
{
|
||||
[CompareField("setupzone_id")]
|
||||
public int SetupZoneId { get; set; }
|
||||
|
||||
public override Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
var baseParams = base.GetParameters();
|
||||
|
||||
baseParams["SETUPZONE_ID"] = SetupZoneId;
|
||||
|
||||
return baseParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
Tabletop.Core/Models/Surface.cs
Normal file
59
Tabletop.Core/Models/Surface.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Surface : LocalizationModelBase<SurfaceDescription>, IDbModel<int?>
|
||||
{
|
||||
[CompareField("surface_id")]
|
||||
public int SurfaceId { get; set; }
|
||||
|
||||
[CompareField("image")]
|
||||
public byte[]? Image { get; set; }
|
||||
|
||||
public string ConvertedImage { get; set; } = string.Empty;
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return SurfaceId > 0 ? SurfaceId : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Dictionary<string, object?>> GetLocalizedParameters()
|
||||
{
|
||||
foreach (var description in Description)
|
||||
{
|
||||
yield return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SURFACE_ID", SurfaceId },
|
||||
{ "NAME", description.Name },
|
||||
{ "DESCRIPTION", description.Description }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SURFACE_ID", SurfaceId },
|
||||
{ "IMAGE", Image }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class SurfaceDescription : ILocalizationHelper
|
||||
{
|
||||
[CompareField("surface_id")]
|
||||
public int SurfaceId { get; set; }
|
||||
|
||||
[CompareField("code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
27
Tabletop.Core/Models/Team.cs
Normal file
27
Tabletop.Core/Models/Team.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Team
|
||||
{
|
||||
[CompareField("team_id")]
|
||||
public int TeamId { get; set; }
|
||||
[CompareField("game_id")]
|
||||
public int GameId { get; set; }
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
[CompareField("points")]
|
||||
public int Points { get; set; }
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "TEAM_ID", TeamId },
|
||||
{ "GAME_ID", GameId },
|
||||
{ "NAME", Name },
|
||||
{ "POINTS", Points}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Tabletop.Core/Models/Template.cs
Normal file
34
Tabletop.Core/Models/Template.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Template : ArmyBase, IDbModel<int?>
|
||||
{
|
||||
[CompareField("template_id")]
|
||||
public int TemplateId { get; set; }
|
||||
[CompareField("user_id")]
|
||||
public int UserId { get; set; }
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
[CompareField("force")]
|
||||
public int Force { get; set; }
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return TemplateId > 0 ? TemplateId : null;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
var baseParams = base.GetParameters();
|
||||
|
||||
baseParams["TEMPLATE_ID"] = TemplateId;
|
||||
baseParams["USER_ID"] = UserId;
|
||||
baseParams["NAME"] = Name;
|
||||
baseParams["FORCE"] = Force;
|
||||
|
||||
return baseParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
105
Tabletop.Core/Models/Unit.cs
Normal file
105
Tabletop.Core/Models/Unit.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Unit : LocalizationModelBase<UnitDescription>, IDbModel<int?>
|
||||
{
|
||||
[CompareField("unit_id")]
|
||||
public int UnitId { get; set; }
|
||||
|
||||
[CompareField("fraction_id")]
|
||||
public int FractionId { get; set; }
|
||||
[CompareField("class_id")]
|
||||
public int ClassId { get; set; }
|
||||
[CompareField("troop_quantity")]
|
||||
public int TroopQuantity { get; set; }
|
||||
|
||||
[CompareField("defense")]
|
||||
public int Defense { get; set; }
|
||||
|
||||
[CompareField("moving")]
|
||||
public int Moving { get; set; }
|
||||
|
||||
[CompareField("primary_weapon_id")]
|
||||
public int PrimaryWeaponId { get; set; }
|
||||
|
||||
[CompareField("secondary_weapon_id")]
|
||||
public int? SecondaryWeaponId { get; set; }
|
||||
[CompareField("first_ability_id")]
|
||||
public int? FirstAbilityId { get; set; }
|
||||
[CompareField("second_ability_id")]
|
||||
public int? SecondAbilityId { get; set; }
|
||||
|
||||
[CompareField("image")]
|
||||
public byte[]? Image { get; set; }
|
||||
public int Force { get; set; }
|
||||
public string ConvertedImage { get; set; } = string.Empty;
|
||||
|
||||
public Weapon? PrimaryWeapon { get; set; }
|
||||
public Weapon? SecondaryWeapon { get; set; }
|
||||
public Class? Class { get; set; }
|
||||
public Ability? FirstAbility { get; set; }
|
||||
public Ability? SecondAbility { get; set; }
|
||||
|
||||
[CompareField("quantity")]
|
||||
public int Quantity { get; set; }
|
||||
public int ForceOfQuantity { get; set; }
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return UnitId > 0 ? UnitId : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Dictionary<string, object?>> GetLocalizedParameters()
|
||||
{
|
||||
foreach (var description in Description)
|
||||
{
|
||||
yield return new Dictionary<string, object?>
|
||||
{
|
||||
{ "UNIT_ID", UnitId },
|
||||
{ "NAME", description.Name },
|
||||
{ "DESCRIPTION", description.Description },
|
||||
{ "MECHANIC", description.Mechanic }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "UNIT_ID", UnitId },
|
||||
{ "FRACTION_ID", FractionId },
|
||||
{ "CLASS_ID", ClassId },
|
||||
{ "TROOP_QUANTITY", TroopQuantity },
|
||||
{ "DEFENSE", Defense },
|
||||
{ "MOVING", Moving },
|
||||
{ "PRIMARY_WEAPON_ID", PrimaryWeaponId },
|
||||
{ "SECONDARY_WEAPON_ID", SecondaryWeaponId },
|
||||
{ "FIRST_ABILITY_ID", FirstAbilityId },
|
||||
{ "SECOND_ABILITY_ID" , SecondAbilityId },
|
||||
{ "QUANTITY", Quantity }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class UnitDescription : ILocalizationHelper
|
||||
{
|
||||
[CompareField("unit_id")]
|
||||
public int UnitId { get; set; }
|
||||
|
||||
[CompareField("code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("mechanic")]
|
||||
public string Mechanic { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
56
Tabletop.Core/Models/User.cs
Normal file
56
Tabletop.Core/Models/User.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public sealed class User : IDbModel<int?>
|
||||
{
|
||||
[CompareField("user_id")]
|
||||
public int UserId { get; set; }
|
||||
[CompareField("username")]
|
||||
public string Username { get; set; } = string.Empty;
|
||||
[CompareField("display_name")]
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
[CompareField("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
[CompareField("main_fraction_id")]
|
||||
public int MainFractionId { get; set; }
|
||||
[CompareField("password")]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
[CompareField("salt")]
|
||||
public string Salt { get; set; } = string.Empty;
|
||||
[CompareField("last_login")]
|
||||
public DateTime LastLogin { get; set; }
|
||||
[CompareField("registration_date")]
|
||||
public DateTime RegistrationDate { get; set; }
|
||||
[CompareField("image")]
|
||||
public byte[]? Image { get; set; }
|
||||
|
||||
public string ConvertedImage { get; set; } = string.Empty;
|
||||
|
||||
|
||||
public List<Permission> Permissions { get; set; } = [];
|
||||
public List<Unit> Units { get; set; } = [];
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return UserId > 0 ? UserId : null;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "USER_ID", UserId },
|
||||
{ "USERNAME", Username },
|
||||
{ "DISPLAY_NAME", DisplayName },
|
||||
{ "DESCRIPTION", Description },
|
||||
{ "MAIN_FRACTION_ID", MainFractionId },
|
||||
{ "PASSWORD", Password },
|
||||
{ "SALT", Salt },
|
||||
{ "LAST_LOGIN", LastLogin },
|
||||
{ "REGISTRATION_DATE", RegistrationDate },
|
||||
{ "IMAGE", Image }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Tabletop.Core/Models/UserPermission.cs
Normal file
12
Tabletop.Core/Models/UserPermission.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using DbController;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public sealed class UserPermission
|
||||
{
|
||||
[CompareField("user_id")]
|
||||
public int UserId { get; set; }
|
||||
[CompareField("permission_id")]
|
||||
public int PermissionId { get; set; }
|
||||
}
|
||||
}
|
||||
69
Tabletop.Core/Models/Weapon.cs
Normal file
69
Tabletop.Core/Models/Weapon.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models.Abstract;
|
||||
|
||||
namespace Tabletop.Core.Models
|
||||
{
|
||||
public class Weapon : LocalizationModelBase<WeaponDescription>, IDbModel<int?>
|
||||
{
|
||||
[CompareField("weapon_id")]
|
||||
public int WeaponId { get; set; }
|
||||
|
||||
[CompareField("attack")]
|
||||
public int Attack { get; set; }
|
||||
|
||||
[CompareField("quality")]
|
||||
public int Quality { get; set; }
|
||||
|
||||
[CompareField("range")]
|
||||
public int Range { get; set; }
|
||||
|
||||
[CompareField("dices")]
|
||||
public int Dices { get; set; }
|
||||
|
||||
public int? GetIdentifier()
|
||||
{
|
||||
return WeaponId > 0 ? WeaponId : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Dictionary<string, object?>> GetLocalizedParameters()
|
||||
{
|
||||
foreach (var description in Description)
|
||||
{
|
||||
yield return new Dictionary<string, object?>
|
||||
{
|
||||
{ "PERMISSION_ID", WeaponId },
|
||||
{ "NAME", description.Name },
|
||||
{ "DESCRIPTION", description.Description }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetParameters()
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "WEAPON_ID", WeaponId },
|
||||
{ "ATTACK", Attack },
|
||||
{ "QUALITY", Quality },
|
||||
{ "RANGE", Range },
|
||||
{ "DICES", Dices }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class WeaponDescription : ILocalizationHelper
|
||||
{
|
||||
[CompareField("weapon_id")]
|
||||
public int WeaponId { get; set; }
|
||||
|
||||
[CompareField("code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[CompareField("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
209
Tabletop.Core/Services/AbilityService.cs
Normal file
209
Tabletop.Core/Services/AbilityService.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using DbController;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Tabletop.Core.Filters;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class AbilityService : IModelService<Ability, int, AbilityFilter>
|
||||
{
|
||||
public async Task CreateAsync(Ability input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = $@"INSERT INTO Fractions
|
||||
(
|
||||
Quality,
|
||||
Force
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@QUALITY,
|
||||
@FORCE
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.AbilityId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"INSERT INTO AbilityDescription
|
||||
(
|
||||
AbilityId,
|
||||
Code,
|
||||
Name,
|
||||
Description,
|
||||
Mechanic
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@ABILITY_ID,
|
||||
@CODE,
|
||||
@NAME,
|
||||
@DESCRIPTION,
|
||||
@MECHANIC
|
||||
)";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
ABILTIY_ID = input.AbilityId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
DESCRIPTION = description.Description
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Ability input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "DELETE FROM Abilities WHERE AbilityId = @ABILITY_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
ABILITY_ID = input.AbilityId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task<List<Ability>> GetAllAsync(IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "SELECT * FROM Abilities";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Ability>(sql, cancellationToken: cancellationToken);
|
||||
await LoadClassDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<Ability?> GetAsync(int abilityId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = @"SELECT * FROM Abilities WHERE AbilityId = @ABILITY_ID";
|
||||
|
||||
var ability = await dbController.GetFirstAsync<Ability>(sql, new
|
||||
{
|
||||
ABILITY_ID = abilityId
|
||||
}, cancellationToken);
|
||||
|
||||
return ability;
|
||||
}
|
||||
|
||||
private static async Task LoadClassDescriptionsAsync(List<Ability> list, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
IEnumerable<int> abilityIds = list.Select(x => x.AbilityId);
|
||||
string sql = $"SELECT * FROM AbilityDescription WHERE AbilityId IN ({string.Join(",", abilityIds)})";
|
||||
List<AbilityDescription> descriptions = await dbController.SelectDataAsync<AbilityDescription>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
item.Description = [.. descriptions.Where(x => x.AbilityId == item.AbilityId)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Ability input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = @"UPDATE Abilities SET
|
||||
Quality = @QUALITY,
|
||||
Force = @FORCE
|
||||
WHERE AbilityId = @ABILITY_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"UPDATE AbilityDescription SET
|
||||
Name = @NAME,
|
||||
Description = @DESCRIPTION,
|
||||
Mechanic = @MECHANIC
|
||||
WHERE AbilityId = @ABILITY_ID AND Code = @CODE";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
ABILITY_ID = input.AbilityId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
DESCRIPTION = description.Description,
|
||||
MECHANIC = description.Mechanic
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<Ability>> GetAsync(AbilityFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT ad.Name, a.* " +
|
||||
"FROM AbilityDescription ad " +
|
||||
"INNER JOIN Abilities a " +
|
||||
"ON (a.AbilityId = ad.AbilityId) " +
|
||||
"WHERE 1 = 1");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
sqlBuilder.AppendLine(@$" ORDER BY Name ASC ");
|
||||
sqlBuilder.AppendLine(dbController.GetPaginationSyntax(filter.PageNumber, filter.Limit));
|
||||
|
||||
// Zum Debuggen schreiben wir den Wert einmal als Variabel
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
List<Ability> list = await dbController.SelectDataAsync<Ability>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
await LoadAbilityDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalAsync(AbilityFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT COUNT(*) AS record_count FROM AbilityDescription WHERE 1 = 1 ");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
int result = await dbController.GetFirstAsync<int>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string GetFilterWhere(AbilityFilter filter)
|
||||
{
|
||||
StringBuilder sqlBuilder = new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchPhrase))
|
||||
{
|
||||
sqlBuilder.AppendLine(@" AND (UPPER(Name) LIKE @SEARCHPHRASE)");
|
||||
}
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetFilterParameter(AbilityFilter filter)
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SEARCHPHRASE", $"%{filter.SearchPhrase}%" },
|
||||
{ "CULTURE", CultureInfo.CurrentCulture.Name }
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task LoadAbilityDescriptionsAsync(List<Ability> list, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
IEnumerable<int> abilityIds = list.Select(x => x.AbilityId);
|
||||
string sql = $"SELECT * FROM AbilityDescription WHERE AbilityId IN ({string.Join(",", abilityIds)})";
|
||||
List<AbilityDescription> descriptions = await dbController.SelectDataAsync<AbilityDescription>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var ability in list)
|
||||
{
|
||||
ability.Description = [.. descriptions.Where(x => x.AbilityId == ability.AbilityId)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
128
Tabletop.Core/Services/AppdataService.cs
Normal file
128
Tabletop.Core/Services/AppdataService.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using DbController;
|
||||
using DbController.SqlServer;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Globalization;
|
||||
using Tabletop.Core.Interfaces;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public static class AppdataService
|
||||
{
|
||||
public static string[] SupportedCultureCodes => [.. SupportedCultures.Select(x => x.Name)];
|
||||
|
||||
public static CultureInfo[] SupportedCultures =>
|
||||
[
|
||||
new ("en"),
|
||||
new ("de")
|
||||
];
|
||||
|
||||
public static bool FirstUserExists { get; set; } = false;
|
||||
|
||||
public static List<Permission> Permissions { get; set; } = [];
|
||||
|
||||
public static List<Unit> Units { get; set; } = [];
|
||||
public static List<Weapon> Weapons { get; set; } = [];
|
||||
public static List<Fraction> Fractions { get; set; } = [];
|
||||
public static List<Gamemode> Gamemodes { get; set; } = [];
|
||||
public static List<Class> Classes { get; set; } = [];
|
||||
public static List<Ability> Abilities { get; set; } = [];
|
||||
public static List<Layout> Layouts { get; set; } = [];
|
||||
public static List<Surface> Surfaces { get; set; } = [];
|
||||
|
||||
|
||||
public static readonly Dictionary<string, Game> Games = [];
|
||||
|
||||
|
||||
|
||||
private static IConfiguration? _configuration;
|
||||
|
||||
public static async Task InitAsync(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
using IDbController dbController = new SqlController(ConnectionString);
|
||||
Permissions = await PermissionService.GetAllAsync(dbController);
|
||||
FirstUserExists = await UserService.FirstUserExistsAsync(dbController);
|
||||
|
||||
Units = await UnitService.GetAllAsync(dbController);
|
||||
Weapons = await WeaponService.GetAllAsync(dbController);
|
||||
Fractions = await FractionService.GetAllAsync(dbController);
|
||||
Gamemodes = await GamemodeService.GetAllAsync(dbController);
|
||||
Classes = await ClassService.GetAllAsync(dbController);
|
||||
Abilities = await AbilityService.GetAllAsync(dbController);
|
||||
Layouts = await LayoutService.GetAllAsync(dbController);
|
||||
Surfaces = await SurfaceService.GetAllAsync(dbController);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates or updates an object in the corresponding list fro the type <see cref="T"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="input"></param>
|
||||
public static void UpdateRecord<T>(T input) where T : class, IDbModel<int?>, new()
|
||||
{
|
||||
List<T> list = GetList<T>();
|
||||
|
||||
T? item = list.FirstOrDefault(x => x.GetIdentifier() == input.GetIdentifier());
|
||||
|
||||
if (item is null)
|
||||
{
|
||||
list.Add(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = list.IndexOf(item);
|
||||
list[index] = input;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an item from the corresponding object list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="input"></param>
|
||||
public static void DeleteRecord<T>(T input) where T : class, IDbModel<int?>, new()
|
||||
{
|
||||
List<T> list = GetList<T>();
|
||||
list.Remove(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the corresponding list for the type <see cref="T"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns>This method never returns null. When no list for <see cref="T"/> is specified, it returns a new empty list</returns>
|
||||
public static List<T> GetList<T>() where T : class, IDbModel<int?>, new()
|
||||
{
|
||||
var input = new T();
|
||||
object tmp = input switch
|
||||
{
|
||||
Permission => Permissions,
|
||||
_ => new List<T>()
|
||||
};
|
||||
|
||||
List<T> list = (List<T>)tmp;
|
||||
return list;
|
||||
}
|
||||
|
||||
public static string ConnectionString => _configuration?["Sql:ConnectionString"] ?? string.Empty;
|
||||
public static int PageLimit => _configuration?.GetValue<int>("Filter:PageLimit") ?? 30;
|
||||
public static string ApiKey => _configuration?["IpGeolocation:ApiKey"] ?? string.Empty;
|
||||
|
||||
public static CultureInfo ToCulture(this ILocalizationHelper helper)
|
||||
{
|
||||
|
||||
var culture = SupportedCultures.FirstOrDefault(x => x.TwoLetterISOLanguageName.Equals(helper.Code, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (culture is null)
|
||||
{
|
||||
return SupportedCultures[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return culture;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Tabletop.Core/Services/AuthService.cs
Normal file
62
Tabletop.Core/Services/AuthService.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using DbController;
|
||||
using DbController.SqlServer;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using System.Security.Claims;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class AuthService(AuthenticationStateProvider authenticationStateProvider, UserService userService)
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Converts the active claims into a <see cref="User"/> object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<User?> GetUserAsync(IDbController? dbController = null)
|
||||
{
|
||||
|
||||
var authState = await authenticationStateProvider.GetAuthenticationStateAsync();
|
||||
var user = authState.User;
|
||||
if (user.Identity is not null && user.Identity.IsAuthenticated)
|
||||
{
|
||||
Claim? claim = user.FindFirst("UserId");
|
||||
if (claim is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var userId = Convert.ToInt32(claim.Value);
|
||||
|
||||
bool shouldDispose = dbController is null;
|
||||
|
||||
|
||||
dbController ??= new SqlController(AppdataService.ConnectionString);
|
||||
|
||||
var result = await userService.GetAsync(userId, dbController);
|
||||
|
||||
if (shouldDispose)
|
||||
{
|
||||
dbController.Dispose();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the currently logged in user as a specific role within it's claims.
|
||||
/// </summary>
|
||||
/// <param name="roleName"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> HasRole(string roleName)
|
||||
{
|
||||
var authState = await authenticationStateProvider.GetAuthenticationStateAsync();
|
||||
var user = authState.User;
|
||||
|
||||
return user.IsInRole(roleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Tabletop.Core/Services/CaptureService.cs
Normal file
12
Tabletop.Core/Services/CaptureService.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
internal class CaptureService
|
||||
{
|
||||
}
|
||||
}
|
||||
53
Tabletop.Core/Services/ClassServices.cs
Normal file
53
Tabletop.Core/Services/ClassServices.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class ClassService : IModelService<Class, int>
|
||||
{
|
||||
public Task CreateAsync(Class input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task DeleteAsync(Class input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static async Task<List<Class>> GetAllAsync(IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "SELECT * FROM Classes";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Class>(sql, cancellationToken: cancellationToken);
|
||||
await LoadClassDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public Task<Class?> GetAsync(int identifier, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static async Task LoadClassDescriptionsAsync(List<Class> list, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
IEnumerable<int> classIds = list.Select(x => x.ClassId);
|
||||
string sql = $"SELECT * FROM ClassDescription WHERE ClassId IN ({string.Join(",", classIds)})";
|
||||
List<ClassDescription> descriptions = await dbController.SelectDataAsync<ClassDescription>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
item.Description = [.. descriptions.Where(x => x.ClassId == item.ClassId)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task UpdateAsync(Class input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
132
Tabletop.Core/Services/ConnectionLogService.cs
Normal file
132
Tabletop.Core/Services/ConnectionLogService.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using DbController;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class ConnectionLogService(GeolocationService geolocationService)
|
||||
{
|
||||
private readonly GeolocationService _geolocationService = geolocationService;
|
||||
|
||||
public static async Task CreateAsync(ConnectionLog input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// SQL-Insert-Statement für das ConnectionLog
|
||||
string sql = $@"
|
||||
INSERT INTO ConnectionLogs
|
||||
(
|
||||
IpAddress,
|
||||
ConnectionTime,
|
||||
UserAgent,
|
||||
Referrer,
|
||||
RequestedUrl,
|
||||
Geolocation,
|
||||
SessionId,
|
||||
StatusCode,
|
||||
DeviceType,
|
||||
OperatingSystem
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@IP_ADDRESS,
|
||||
@CONNECTION_TIME,
|
||||
@USER_AGENT,
|
||||
@REFERRER,
|
||||
@REQUESTED_URL,
|
||||
@GEOLOCATION,
|
||||
@SESSION_ID,
|
||||
@STATUS_CODE,
|
||||
@DEVICE_TYPE,
|
||||
@OPERATING_SYSTEM
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<ConnectionLog> GetConnectionLogAsync(HttpContext context)
|
||||
{
|
||||
// Extrahiere die IP-Adresse
|
||||
var ipAddress = context.Connection.RemoteIpAddress?.ToString() ?? "Unknown";
|
||||
|
||||
// Hole die Geolocation (Stadt, Land, Koordinaten etc.) basierend auf der IP-Adresse
|
||||
var geolocation = await _geolocationService.GetGeolocationAsync(ipAddress);
|
||||
|
||||
// Extrahiere den User-Agent-Header aus dem HttpContext
|
||||
var userAgent = context.Request.Headers["User-Agent"].FirstOrDefault() ?? "Unknown";
|
||||
|
||||
// Bestimmung des DeviceTypes und des Betriebssystems
|
||||
var deviceType = await GetDeviceType(userAgent);
|
||||
var operatingSystem = await GetOperatingSystem(userAgent);
|
||||
|
||||
// Erstelle das ConnectionLog
|
||||
return new ConnectionLog
|
||||
{
|
||||
IpAddress = ipAddress,
|
||||
ConnectionTime = DateTime.UtcNow,
|
||||
UserAgent = userAgent,
|
||||
Referrer = context.Request.Headers["Referer"].FirstOrDefault() ?? "Unknown",
|
||||
RequestedUrl = context.Request.Path,
|
||||
Geolocation = geolocation, // Füge die Geolocation hinzu
|
||||
SessionId = context.Session?.Id ?? Guid.NewGuid().ToString(),
|
||||
StatusCode = context.Response.StatusCode,
|
||||
DeviceType = deviceType,
|
||||
OperatingSystem = operatingSystem
|
||||
};
|
||||
}
|
||||
|
||||
// Methode zur Bestimmung des Device-Typs anhand des User-Agent-Strings
|
||||
public static Task<string> GetDeviceType(string userAgent)
|
||||
{
|
||||
string deviceType;
|
||||
|
||||
if (userAgent.Contains("Mobi") || userAgent.Contains("Android") || userAgent.Contains("iPhone") || userAgent.Contains("iPad"))
|
||||
{
|
||||
deviceType = "Mobile";
|
||||
}
|
||||
else if (userAgent.Contains("Tablet") || userAgent.Contains("iPad"))
|
||||
{
|
||||
deviceType = "Tablet";
|
||||
}
|
||||
else
|
||||
{
|
||||
deviceType = "Desktop"; // Default ist Desktop
|
||||
}
|
||||
|
||||
return Task.FromResult(deviceType); // Verpackt den Wert in einem Task
|
||||
}
|
||||
|
||||
// Methode zur Bestimmung des Betriebssystems anhand des User-Agent-Strings
|
||||
public static Task<string> GetOperatingSystem(string userAgent)
|
||||
{
|
||||
string operatingSystem;
|
||||
|
||||
if (userAgent.Contains("Windows"))
|
||||
{
|
||||
operatingSystem = "Windows";
|
||||
}
|
||||
else if (userAgent.Contains("Mac OS"))
|
||||
{
|
||||
operatingSystem = "macOS";
|
||||
}
|
||||
else if (userAgent.Contains("Linux"))
|
||||
{
|
||||
operatingSystem = "Linux";
|
||||
}
|
||||
else if (userAgent.Contains("Android"))
|
||||
{
|
||||
operatingSystem = "Android";
|
||||
}
|
||||
else if (userAgent.Contains("iPhone") || userAgent.Contains("iPad"))
|
||||
{
|
||||
operatingSystem = "iOS";
|
||||
}
|
||||
else
|
||||
{
|
||||
operatingSystem = "Other"; // Default: Unbekanntes Betriebssystem
|
||||
}
|
||||
|
||||
return Task.FromResult(operatingSystem); // Verpackt den Wert in einem Task
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Tabletop.Core/Services/EliminationService.cs
Normal file
12
Tabletop.Core/Services/EliminationService.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
internal class EliminationService
|
||||
{
|
||||
}
|
||||
}
|
||||
189
Tabletop.Core/Services/FractionService.cs
Normal file
189
Tabletop.Core/Services/FractionService.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using DbController;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Tabletop.Core.Filters;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class FractionService : IModelService<Fraction, int, FractionFilter>
|
||||
{
|
||||
public async Task CreateAsync(Fraction input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = $@"INSERT INTO Fractions
|
||||
(
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.FractionId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"INSERT INTO FractionDescription
|
||||
(
|
||||
FractionId,
|
||||
Code,
|
||||
Name,
|
||||
ShortName,
|
||||
Description
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@FRACTION_ID,
|
||||
@CODE,
|
||||
@NAME,
|
||||
@SHORT_NAME,
|
||||
@DESCRIPTION
|
||||
)";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
FRACTION_ID = input.FractionId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
SHORT_NAME = description.ShortName,
|
||||
DESCRIPTION = description.Description
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Fraction input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "DELETE FROM Fractions WHERE FractionId = @FRACTION_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
FRACTION_ID = input.FractionId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Fraction?> GetAsync(int fractionId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = @"SELECT * FROM Fractions WHERE FractionId = @FRACTION_ID";
|
||||
|
||||
var fraction = await dbController.GetFirstAsync<Fraction>(sql, new
|
||||
{
|
||||
FRACTION_ID = fractionId
|
||||
}, cancellationToken);
|
||||
|
||||
return fraction;
|
||||
}
|
||||
|
||||
public static async Task<List<Fraction>> GetAllAsync(IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "SELECT * FROM Fractions";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Fraction>(sql, cancellationToken: cancellationToken);
|
||||
await LoadFractionDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Fraction input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = @"UPDATE Fractions SET
|
||||
Image = @IMAGE
|
||||
WHERE FractionId = @FRACTION_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"UPDATE FractionDescription SET
|
||||
Name = @NAME,
|
||||
Description = @DESCRIPTION,
|
||||
ShortName = @SHORT_NAME
|
||||
WHERE FractionId = @FRACTION_ID AND Code = @CODE";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
FRACTION_ID = input.FractionId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
SHORT_NAME = description.ShortName,
|
||||
DESCRIPTION = description.Description
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<Fraction>> GetAsync(FractionFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT fd.Name, f.* " +
|
||||
"FROM FractionDescription fd " +
|
||||
"INNER JOIN Fractions f " +
|
||||
"ON (f.FractionId = fd.FractionId) " +
|
||||
"WHERE 1 = 1");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
sqlBuilder.AppendLine(@$" ORDER BY Name ASC ");
|
||||
sqlBuilder.AppendLine(dbController.GetPaginationSyntax(filter.PageNumber, filter.Limit));
|
||||
|
||||
// Zum Debuggen schreiben wir den Wert einmal als Variabel
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
List<Fraction> list = await dbController.SelectDataAsync<Fraction>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
await LoadFractionDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalAsync(FractionFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT COUNT(*) AS record_count FROM FractionDescription WHERE 1 = 1 ");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
int result = await dbController.GetFirstAsync<int>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string GetFilterWhere(FractionFilter filter)
|
||||
{
|
||||
StringBuilder sqlBuilder = new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchPhrase))
|
||||
{
|
||||
sqlBuilder.AppendLine(@" AND (UPPER(Name) LIKE @SEARCHPHRASE)");
|
||||
}
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetFilterParameter(FractionFilter filter)
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SEARCHPHRASE", $"%{filter.SearchPhrase}%" },
|
||||
{ "CULTURE", CultureInfo.CurrentCulture.Name }
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task LoadFractionDescriptionsAsync(List<Fraction> list, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
IEnumerable<int> fractionIds = list.Select(x => x.FractionId);
|
||||
string sql = $"SELECT * FROM FractionDescription WHERE FractionId IN ({string.Join(",", fractionIds)})";
|
||||
List<FractionDescription> descriptions = await dbController.SelectDataAsync<FractionDescription>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var fraction in list)
|
||||
{
|
||||
fraction.Description = [.. descriptions.Where(x => x.FractionId == fraction.FractionId)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
182
Tabletop.Core/Services/GameService.cs
Normal file
182
Tabletop.Core/Services/GameService.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
using DbController;
|
||||
using System.Text;
|
||||
using Tabletop.Core.Filters;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class GameService(PlayerService playerService, UserService userService) : IModelService<Game, int, GameFilter>
|
||||
{
|
||||
private readonly PlayerService _playerService = playerService;
|
||||
private readonly UserService _userService = userService;
|
||||
|
||||
public async Task CreateAsync(Game input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = $@"INSERT INTO Games
|
||||
(
|
||||
UserId,
|
||||
GamemodeId,
|
||||
SurfaceId,
|
||||
LayoutId,
|
||||
Name,
|
||||
NumberOfRounds,
|
||||
Force,
|
||||
NumberOfTeams,
|
||||
NumberOfPlayers,
|
||||
Date
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@USER_ID,
|
||||
@GAMEMODE_ID,
|
||||
@SURFACE_ID,
|
||||
@LAYOUT_ID,
|
||||
@NAME,
|
||||
@NUMBER_OF_ROUNDS,
|
||||
@FORCE,
|
||||
@NUMBER_OF_TEAMS,
|
||||
@NUMBER_OF_PLAYERS,
|
||||
@DATE
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.GameId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var item in input.Players)
|
||||
{
|
||||
item.GameId = input.GameId;
|
||||
await _playerService.CreateAsync(item, dbController, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Game input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "DELETE FROM Games WHERE GameId = @GAME_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
GAME_ID = input.GameId,
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Game?> GetAsync(int gameId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT * FROM Games WHERE GameId = @GAME_ID";
|
||||
|
||||
var game = await dbController.GetFirstAsync<Game>(sql, new
|
||||
{
|
||||
GAME_ID = gameId
|
||||
}, cancellationToken);
|
||||
|
||||
if (game != null)
|
||||
{
|
||||
game.Players = await _playerService.GetGamePlayersAsync(game.GameId, dbController, cancellationToken);
|
||||
}
|
||||
|
||||
return game;
|
||||
}
|
||||
|
||||
public static async Task<List<Game>> GetAllAsync(IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "SELECT * FROM Games";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Game>(sql, cancellationToken: cancellationToken);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<List<Game>> GetAsync(GameFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sb = new();
|
||||
sb.AppendLine("SELECT DISTINCT g.* FROM Games g LEFT JOIN Players p ON g.GameId = p.GameId WHERE p.UserId = @USER_ID OR g.UserId = @USER_ID ");
|
||||
sb.AppendLine(GetFilterWhere(filter));
|
||||
sb.AppendLine(@$" ORDER BY Date DESC ");
|
||||
sb.AppendLine(dbController.GetPaginationSyntax(filter.PageNumber, filter.Limit));
|
||||
|
||||
string sql = sb.ToString();
|
||||
|
||||
List<Game> list = await dbController.SelectDataAsync<Game>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
if (list.Count != 0)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
item.Players = await _playerService.GetGamePlayersAsync(item.GameId, dbController, cancellationToken);
|
||||
item.Host = await _userService.GetUsernameAsync(item.UserId, dbController, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<List<Game>> GetLastGamesOfPlayerAsync(int userId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "SELECT TOP 5 g.GameId, g.GamemodeId, g.Date, g.Force FROM Games g INNER JOIN Players p ON g.GameId = p.GameId WHERE p.UserId = @USER_ID ORDER BY g.Date DESC";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Game>(sql, new
|
||||
{
|
||||
USER_ID = userId,
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetFilterParameter(GameFilter filter)
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SEARCHPHRASE", $"%{filter.SearchPhrase}%" },
|
||||
{ "USER_ID", filter.UserId }
|
||||
};
|
||||
}
|
||||
|
||||
public string GetFilterWhere(GameFilter filter)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchPhrase))
|
||||
{
|
||||
sb.AppendLine(@" AND (UPPER(Name) LIKE @SEARCHPHRASE)");
|
||||
}
|
||||
|
||||
string sql = sb.ToString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalAsync(GameFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sb = new();
|
||||
sb.AppendLine("SELECT COUNT(*) FROM Games WHERE UserId = @USER_ID");
|
||||
sb.AppendLine(GetFilterWhere(filter));
|
||||
|
||||
string sql = sb.ToString();
|
||||
|
||||
int result = await dbController.GetFirstAsync<int>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Game input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = @"UPDATE Games SET
|
||||
GamemodeId = @GAMEMODE_ID,
|
||||
SurfaceId = @SURFACE_ID,
|
||||
LayoutId = @LAYOUT_ID,
|
||||
Name = @NAME,
|
||||
NumberOfRounds = @NUMBER_OF_ROUNDS,
|
||||
Force = @FORCE,
|
||||
NumberOfTeams = @NUMBER_OF_TEAMS,
|
||||
NumberOfPlayers = @NUMBER_OF_PLAYERS,
|
||||
Date = @DATE
|
||||
WHERE GameId = @GAME_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
189
Tabletop.Core/Services/GamemodeService.cs
Normal file
189
Tabletop.Core/Services/GamemodeService.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using DbController;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Tabletop.Core.Filters;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class GamemodeService : IModelService<Gamemode, int, GamemodeFilter>
|
||||
{
|
||||
public async Task CreateAsync(Gamemode input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = $@"INSERT INTO Gamemodes
|
||||
(
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.GamemodeId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"INSERT INTO GamemodeDescription
|
||||
(
|
||||
GamemodeId,
|
||||
Code,
|
||||
Name,
|
||||
Description,
|
||||
Mechanic
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@GAMEMODE_ID,
|
||||
@CODE,
|
||||
@NAME,
|
||||
@DESCRIPTION,
|
||||
@MECHANIC
|
||||
)";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
GAMEMODE_ID = input.GamemodeId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
DESCRIPTION = description.Description
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Gamemode input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "DELETE FROM Gamemodes WHERE GamemodeId = @GAMEMODE_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
GAMEMODE_ID = input.GamemodeId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Gamemode?> GetAsync(int gamemodeId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = @"SELECT * FROM Gamemodes WHERE GamemodeId = @GAMEMODE_ID";
|
||||
|
||||
var gamemode = await dbController.GetFirstAsync<Gamemode>(sql, new
|
||||
{
|
||||
GAMEMODE_ID = gamemodeId
|
||||
}, cancellationToken);
|
||||
|
||||
return gamemode;
|
||||
}
|
||||
|
||||
public static async Task<List<Gamemode>> GetAllAsync(IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "SELECT * FROM Gamemodes";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Gamemode>(sql, cancellationToken: cancellationToken);
|
||||
await LoadGamemodeDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Gamemode input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql;
|
||||
//string sql = @"UPDATE Gamemodes SET
|
||||
// Image = @IMAGE
|
||||
// WHERE GamemodeId = @GAMEMODE_ID";
|
||||
|
||||
//await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"UPDATE GamemodeDescription SET
|
||||
Name = @NAME,
|
||||
Description = @DESCRIPTION,
|
||||
Mechanic = @MECHANIC
|
||||
WHERE GamemodeId = @GAMEMODE_ID AND Code = @CODE";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
GAMEMODE_ID = input.GamemodeId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
DESCRIPTION = description.Description,
|
||||
MECHANIC = description.Mechanic
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<Gamemode>> GetAsync(GamemodeFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT gd.Name, g.* " +
|
||||
"FROM GamemodeDescription gd " +
|
||||
"INNER JOIN Gamemodes g " +
|
||||
"ON (g.GamemodeId = gd.GamemodeId) " +
|
||||
"WHERE 1 = 1");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
sqlBuilder.AppendLine(@$" ORDER BY Name ASC ");
|
||||
sqlBuilder.AppendLine(dbController.GetPaginationSyntax(filter.PageNumber, filter.Limit));
|
||||
|
||||
// Zum Debuggen schreiben wir den Wert einmal als Variabel
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
List<Gamemode> list = await dbController.SelectDataAsync<Gamemode>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
await LoadGamemodeDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalAsync(GamemodeFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT COUNT(*) AS record_count FROM GamemodeDescription WHERE 1 = 1 ");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
int result = await dbController.GetFirstAsync<int>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string GetFilterWhere(GamemodeFilter filter)
|
||||
{
|
||||
StringBuilder sqlBuilder = new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchPhrase))
|
||||
{
|
||||
sqlBuilder.AppendLine(@" AND (UPPER(Name) LIKE @SEARCHPHRASE)");
|
||||
}
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetFilterParameter(GamemodeFilter filter)
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SEARCHPHRASE", $"%{filter.SearchPhrase}%" },
|
||||
{ "CULTURE", CultureInfo.CurrentCulture.Name }
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task LoadGamemodeDescriptionsAsync(List<Gamemode> list, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
IEnumerable<int> gamemodeIds = list.Select(x => x.GamemodeId);
|
||||
string sql = $"SELECT * FROM GamemodeDescription WHERE GamemodeId IN ({string.Join(",", gamemodeIds)})";
|
||||
List<GamemodeDescription> descriptions = await dbController.SelectDataAsync<GamemodeDescription>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var gamemode in list)
|
||||
{
|
||||
gamemode.Description = [.. descriptions.Where(x => x.GamemodeId == gamemode.GamemodeId)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
Tabletop.Core/Services/GeolocationService.cs
Normal file
51
Tabletop.Core/Services/GeolocationService.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class GeolocationService(HttpClient httpClient)
|
||||
{
|
||||
private readonly HttpClient _httpClient = httpClient;
|
||||
|
||||
public Task<string> GetGeolocationAsync(string ipAddress)
|
||||
{
|
||||
//// Überprüfen, ob die IP-Adresse lokal ist (127.0.0.1 oder localhost)
|
||||
//if (await IsLocalIpAddressAsync(ipAddress))
|
||||
//{
|
||||
// // Wenn es eine lokale IP-Adresse ist, keine Geolokalisierung durchführen
|
||||
// return "Lokale IP-Adresse";
|
||||
//}
|
||||
|
||||
//try
|
||||
//{
|
||||
// // URL für Geolokalisierung
|
||||
// var url = $"https://api.ipgeolocation.io/ipgeo?apiKey={AppdataService.ApiKey}&ip={ipAddress}";
|
||||
|
||||
// // HTTP-Anfrage senden
|
||||
// var response = await _httpClient.GetAsync(url);
|
||||
|
||||
// // Fehlerbehandlung: Prüfen, ob der Statuscode erfolgreich war
|
||||
// response.EnsureSuccessStatusCode(); // Wird eine Ausnahme werfen, wenn der Statuscode nicht erfolgreich ist
|
||||
|
||||
// // Rückgabe der Geolokalisierungsdaten
|
||||
// return await response.Content.ReadAsStringAsync();
|
||||
//}
|
||||
//catch (HttpRequestException ex)
|
||||
//{
|
||||
// // Fehlerbehandlung: Loggen oder Weiterverarbeiten des Fehlers
|
||||
// throw new Exception($"Fehler bei der Geolokalisierung: {ex.Message}", ex);
|
||||
//}
|
||||
return Task.FromResult("Lokale IP-Adresse");
|
||||
}
|
||||
|
||||
// Hilfsmethode, um zu prüfen, ob die IP-Adresse lokal ist
|
||||
private static Task<bool> IsLocalIpAddressAsync(string ipAddress)
|
||||
{
|
||||
// Überprüfen, ob die IP-Adresse eine der folgenden ist
|
||||
bool isLocal = ipAddress == "127.0.0.1" || ipAddress == "localhost" ||
|
||||
ipAddress.StartsWith("10.") || ipAddress.StartsWith("192.168.") ||
|
||||
ipAddress.StartsWith("172.16.");
|
||||
|
||||
return Task.FromResult(isLocal); // Rückgabe des Ergebnisses als Task
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
97
Tabletop.Core/Services/LayoutService.cs
Normal file
97
Tabletop.Core/Services/LayoutService.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class LayoutService : IModelService<Layout, int>
|
||||
{
|
||||
public async Task CreateAsync(Layout input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = $@"INSERT INTO Layouts
|
||||
(
|
||||
GamemodeId,
|
||||
Teams,
|
||||
Width,
|
||||
Height
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@GAMEMODE_ID
|
||||
@TEAMS,
|
||||
@WIDTH,
|
||||
@HEIGHT
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.LayoutId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Layout input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "DELETE FROM Layouts WHERE LayoutId = @LAYOUT_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
LAYOUT_ID = input.LayoutId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task<List<SetupZone>> GetSetupZonesAsync(int layoutId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"
|
||||
SELECT sz.SetupZoneId, sz.LayoutId, z.*
|
||||
FROM SetupZones sz
|
||||
INNER JOIN Zones z ON (z.ZoneId = sz.ZoneId)
|
||||
WHERE sz.LayoutId = @LAYOUT_ID";
|
||||
|
||||
var list = await dbController.SelectDataAsync<SetupZone>(sql, new
|
||||
{
|
||||
LAYOUT_ID = layoutId
|
||||
}, cancellationToken);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static async Task<List<CaptureZone>> GetCaptureZonesAsync(int layoutId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"
|
||||
SELECT cz.CaptureZoneId, cz.LayoutId, z.*
|
||||
FROM CaptureZones cz
|
||||
INNER JOIN Zones z ON (z.ZoneId = cz.ZoneId)
|
||||
WHERE cz.LayoutId = @LAYOUT_ID";
|
||||
|
||||
var list = await dbController.SelectDataAsync<CaptureZone>(sql, new
|
||||
{
|
||||
LAYOUT_ID = layoutId
|
||||
}, cancellationToken);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static async Task<List<Layout>> GetAllAsync(IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "SELECT * FROM Layouts";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Layout>(sql, cancellationToken: cancellationToken);
|
||||
|
||||
foreach(var layout in list)
|
||||
{
|
||||
layout.SetupZones = await GetSetupZonesAsync(layout.LayoutId, dbController, cancellationToken);
|
||||
layout.CaptureZones = await GetCaptureZonesAsync(layout.LayoutId, dbController, cancellationToken);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public Task<Layout?> GetAsync(int battlegroundId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task UpdateAsync(Layout input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Tabletop.Core/Services/MoveService.cs
Normal file
57
Tabletop.Core/Services/MoveService.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class MoveService : IModelService<Move, int>
|
||||
{
|
||||
public async Task CreateAsync(Move input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = $@"INSERT INTO Moves
|
||||
(
|
||||
PlayerId,
|
||||
GameId,
|
||||
TurnNr,
|
||||
MoveNr,
|
||||
StartMove,
|
||||
EndMove
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@PLAYER_ID
|
||||
@GAME_ID,
|
||||
@TURN_NR,
|
||||
@MOVE_NR,
|
||||
@START_MOVE,
|
||||
@END_END
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.MoveId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
}
|
||||
|
||||
public Task DeleteAsync(Move input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Move?> GetAsync(int identifier, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Move input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"UPDATE Moves SET
|
||||
PlayerId = @PLAYER_ID,
|
||||
GameId = @GAME_ID,
|
||||
TurnNr = @TURN_NR,
|
||||
MoveNr = @MOVE_NR,
|
||||
StartMove = @START_MOVE,
|
||||
EndMove = @END_END
|
||||
WHERE MoveId = @MOVE_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
84
Tabletop.Core/Services/PermissionService.cs
Normal file
84
Tabletop.Core/Services/PermissionService.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class PermissionService
|
||||
{
|
||||
public static async Task<List<Permission>> GetUserPermissionsAsync(int userId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT p.*
|
||||
FROM UserPermissions up
|
||||
INNER JOIN Permissions p ON (p.PermissionId = up.PermissionId)
|
||||
WHERE UserId = @USER_ID";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Permission>(sql, new
|
||||
{
|
||||
USER_ID = userId
|
||||
}, cancellationToken);
|
||||
|
||||
await LoadPermissionDescriptionsAsync(list, dbController, cancellationToken);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task UpdateUserPermissionsAsync(User user, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
// Step 1: Delete all permissions for the user.
|
||||
string sql = "DELETE FROM UserPermissions WHERE UserId = @USER_ID";
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
USER_ID = user.UserId
|
||||
}, cancellationToken);
|
||||
|
||||
// Step 2: Add all permissions from the object back.
|
||||
foreach (var permission in user.Permissions)
|
||||
{
|
||||
sql = @"INSERT INTO UserPermissions
|
||||
(
|
||||
UserId,
|
||||
PermissionId
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@USER_ID,
|
||||
@PERMISSION_ID
|
||||
)";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
USER_ID = user.UserId,
|
||||
PERMISSION_ID = permission.PermissionId
|
||||
}, cancellationToken);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<List<Permission>> GetAllAsync(IDbController dbController)
|
||||
{
|
||||
string sql = "SELECT * FROM Permissions";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Permission>(sql);
|
||||
await LoadPermissionDescriptionsAsync(list, dbController);
|
||||
return list;
|
||||
}
|
||||
|
||||
private static async Task LoadPermissionDescriptionsAsync(List<Permission> list, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
IEnumerable<int> permissionIds = list.Select(x => x.PermissionId);
|
||||
string sql = $"SELECT * FROM PermissionDescription WHERE PermissionId IN ({string.Join(",", permissionIds)})";
|
||||
List<PermissionDescription> descriptions = await dbController.SelectDataAsync<PermissionDescription>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var permission in list)
|
||||
{
|
||||
permission.Description = [.. descriptions.Where(x => x.PermissionId == permission.PermissionId)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Tabletop.Core/Services/PlayerService.cs
Normal file
127
Tabletop.Core/Services/PlayerService.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class PlayerService(UserService userService, UnitService unitService) : IModelService<Player, int>
|
||||
{
|
||||
private readonly UserService _userService = userService;
|
||||
private readonly UnitService _unitService = unitService;
|
||||
|
||||
public async Task CreateAsync(Player input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = $@"INSERT INTO Players
|
||||
(
|
||||
UserId,
|
||||
GameId,
|
||||
FractionId,
|
||||
Team,
|
||||
Color,
|
||||
UsedForce
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@USER_ID,
|
||||
@GAME_ID,
|
||||
@FRACTION_ID,
|
||||
@TEAM,
|
||||
@COLOR,
|
||||
@USED_FORCE
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.PlayerId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Player Input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "DELETE FROM Players WHERE PlayerId = @PLAYER_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
Input_ID = Input.PlayerId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task DeleteByGameAsync(int gameId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "DELETE FROM Players WHERE GameId = @GAME_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
GAME_ID = gameId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<Player?> GetAsync(int identifier, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<List<Player>> GetGamePlayersAsync(int gameId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = ("SELECT * FROM Players WHERE GameId = @GAME_ID");
|
||||
|
||||
List<Player> list = await dbController.SelectDataAsync<Player>(sql, new
|
||||
{
|
||||
GAME_ID = gameId
|
||||
}, cancellationToken);
|
||||
|
||||
if (list.Count != 0)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
item.Units = await _unitService.GetPlayerUnitsAsync(item.PlayerId, dbController, cancellationToken);
|
||||
item.User = await _userService.GetUserInformationAsync(item.UserId, dbController, cancellationToken) ?? new();
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Player player, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UnitService.DeletePlayerUnitsAsync(player.PlayerId, dbController, cancellationToken);
|
||||
|
||||
string sql = @"UPDATE Players SET
|
||||
Points = @POINTS
|
||||
WHERE PlayerId = @PLAYER_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, player.GetParameters(), cancellationToken);
|
||||
}
|
||||
|
||||
public async Task UpdatePlayerOrderAsync(Player player, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
string sql = @"UPDATE Players SET
|
||||
OrderNr = @ORDER_NR,
|
||||
StartZone = @START_ZONE
|
||||
WHERE PlayerId = @PLAYER_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, player.GetParameters(), cancellationToken);
|
||||
}
|
||||
|
||||
public async Task UpdatePlayerArmyAsync(Player player, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UnitService.DeletePlayerUnitsAsync(player.PlayerId, dbController, cancellationToken);
|
||||
|
||||
string sql = @"UPDATE Players SET
|
||||
UsedForce = @USED_FORCE
|
||||
WHERE PlayerId = @PLAYER_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, player.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var unit in player.Units)
|
||||
{
|
||||
await _unitService.CreatePlayerUnitAsync(player, unit, dbController, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
112
Tabletop.Core/Services/SurfaceService.cs
Normal file
112
Tabletop.Core/Services/SurfaceService.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using DbController;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class SurfaceService : IModelService<Surface, int>
|
||||
{
|
||||
public async Task CreateAsync(Surface input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = $@"INSERT INTO Surfaces
|
||||
(
|
||||
Image
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@IMAGE
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.SurfaceId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"INSERT INTO SurfaceDescription
|
||||
(
|
||||
SurfaceId,
|
||||
Code,
|
||||
Name,
|
||||
Description
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@SURFACE_ID,
|
||||
@CODE,
|
||||
@NAME,
|
||||
@DESCRIPTION
|
||||
)";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
BATTLEGROUND_ID = input.SurfaceId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
description = description.Description,
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Surface input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "DELETE FROM Surfaces WHERE SurfaceId = @SURFACE_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
SURFACE_ID = input.SurfaceId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task<List<Surface>> GetAllAsync(IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "SELECT * FROM Surfaces";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Surface>(sql, cancellationToken: cancellationToken);
|
||||
|
||||
foreach(var item in list)
|
||||
{
|
||||
if(item.Image != null)
|
||||
{
|
||||
string base64String = Convert.ToBase64String(item.Image);
|
||||
item.ConvertedImage = $"data:image/png;base64,{base64String}";
|
||||
}
|
||||
}
|
||||
|
||||
await LoadSurfaceDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<Surface?> GetAsync(int surfaceId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = @"SELECT * FROM Surfaces WHERE SurfaceId = @SURFACE_ID";
|
||||
|
||||
var surface = await dbController.GetFirstAsync<Surface>(sql, new
|
||||
{
|
||||
SURFACE_ID = surfaceId
|
||||
}, cancellationToken);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
private static async Task LoadSurfaceDescriptionsAsync(List<Surface> list, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
IEnumerable<int> surfaceIds = list.Select(x => x.SurfaceId);
|
||||
string sql = $"SELECT * FROM SurfaceDescription WHERE SurfaceId IN ({string.Join(",", surfaceIds)})";
|
||||
List<SurfaceDescription> descriptions = await dbController.SelectDataAsync<SurfaceDescription>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var battleLocation in list)
|
||||
{
|
||||
battleLocation.Description = [.. descriptions.Where(x => x.SurfaceId == battleLocation.SurfaceId)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task UpdateAsync(Surface input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
171
Tabletop.Core/Services/TemplateService.cs
Normal file
171
Tabletop.Core/Services/TemplateService.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using DbController;
|
||||
using System.Text;
|
||||
using Tabletop.Core.Filters;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class TemplateService : IModelService<Template, int, TemplateFilter>
|
||||
{
|
||||
public async Task CreateAsync(Template input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = $@"INSERT INTO Templates
|
||||
(
|
||||
UserId,
|
||||
FractionId,
|
||||
Name,
|
||||
Force,
|
||||
UsedForce
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@USER_ID,
|
||||
@FRACTION_ID,
|
||||
@NAME,
|
||||
@FORCE,
|
||||
@USED_FORCE
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.TemplateId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach(var unit in input.Units)
|
||||
{
|
||||
await UnitService.CreateTemplateUnitAsync(input.TemplateId, unit, dbController, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Template input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UnitService.DeleteTemplateUnitsAsync(input.TemplateId, dbController, cancellationToken);
|
||||
|
||||
string sql = "DELETE FROM Templates WHERE TemplateId = @TEMPLATE_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
TEMPLATE_ID = input.TemplateId
|
||||
}, cancellationToken);
|
||||
|
||||
}
|
||||
|
||||
public async Task<Template?> GetAsync(int templateId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT * FROM Templates WHERE TemplateId = @TEMPLATE_ID";
|
||||
|
||||
var template = await dbController.GetFirstAsync<Template>(sql, new
|
||||
{
|
||||
TEMPLATE_ID = templateId
|
||||
}, cancellationToken);
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
public static async Task<List<Template>> GetTemplateOnForceAsync(int user_id, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "SELECT * FROM Templates WHERE UserId = @USER_ID";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Template>(sql, new
|
||||
{
|
||||
USER_ID = user_id
|
||||
}, cancellationToken);
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
item.Units = await UnitService.GetTemplateUnitsAsync(item.TemplateId, dbController, cancellationToken);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<List<Template>> GetAsync(TemplateFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sb = new();
|
||||
sb.AppendLine("SELECT * FROM Templates WHERE UserId = @USER_ID");
|
||||
sb.AppendLine(GetFilterWhere(filter));
|
||||
sb.AppendLine(@$" ORDER BY Name ASC");
|
||||
sb.AppendLine(dbController.GetPaginationSyntax(filter.PageNumber, filter.Limit));
|
||||
|
||||
string sql = sb.ToString();
|
||||
|
||||
List<Template> list = await dbController.SelectDataAsync<Template>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
foreach(var item in list)
|
||||
{
|
||||
item.Units = await UnitService.GetTemplateUnitsAsync(item.TemplateId, dbController, cancellationToken);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetFilterParameter(TemplateFilter filter)
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SEARCHPHRASE", $"%{filter.SearchPhrase}%" },
|
||||
{ "USER_ID", filter.UserId },
|
||||
{ "FRACTION_ID", filter.FractionId },
|
||||
{ "FORCE", filter.Force }
|
||||
};
|
||||
}
|
||||
|
||||
public string GetFilterWhere(TemplateFilter filter)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchPhrase))
|
||||
{
|
||||
sb.AppendLine(@" AND (UPPER(Name) LIKE @SEARCHPHRASE)");
|
||||
}
|
||||
if (filter.FractionId != 0)
|
||||
{
|
||||
sb.AppendLine(@" AND FractionId = @FRACTION_ID");
|
||||
}
|
||||
if (filter.Force != 0)
|
||||
{
|
||||
sb.AppendLine(@" AND Force = @FORCE");
|
||||
}
|
||||
|
||||
string sql = sb.ToString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalAsync(TemplateFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sb = new();
|
||||
sb.AppendLine("SELECT COUNT(*) FROM Templates WHERE UserId = @USER_ID");
|
||||
sb.AppendLine(GetFilterWhere(filter));
|
||||
|
||||
string sql = sb.ToString();
|
||||
|
||||
int result = await dbController.GetFirstAsync<int>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Template input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UnitService.DeleteTemplateUnitsAsync(input.TemplateId, dbController, cancellationToken);
|
||||
|
||||
string sql = @"UPDATE Templates SET
|
||||
FractionId = @FRACTION_ID,
|
||||
Name = @NAME,
|
||||
Force = @FORCE,
|
||||
UsedForce = @USED_FORCE
|
||||
WHERE TemplateId = @TEMPLATE_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var unit in input.Units)
|
||||
{
|
||||
await UnitService.CreateTemplateUnitAsync(input.TemplateId, unit, dbController, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
393
Tabletop.Core/Services/UnitService.cs
Normal file
393
Tabletop.Core/Services/UnitService.cs
Normal file
@@ -0,0 +1,393 @@
|
||||
using DbController;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Tabletop.Core.Filters;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class UnitService(WeaponService weaponService) : IModelService<Unit, int, UnitFilter>
|
||||
{
|
||||
private readonly WeaponService _weaponService = weaponService;
|
||||
|
||||
public async Task CreateAsync(Unit input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = $@"INSERT INTO Units
|
||||
(
|
||||
FractionId,
|
||||
ClassId,
|
||||
TroopQuantity,
|
||||
Defense,
|
||||
Moving,
|
||||
PrimaryWeaponId,
|
||||
SecondaryWeaponId,
|
||||
FistAbilityId,
|
||||
SecondAbilityId
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@FRACTION_ID,
|
||||
@CLASS_ID,
|
||||
@TROOP_QUANTITY,
|
||||
@DEFENSE,
|
||||
@MOVING,
|
||||
@PRIMARY_WEAPON_ID,
|
||||
@SECONDARY_WEAPON_ID,
|
||||
@FIRST_ABILITY_ID,
|
||||
@SECOND_ABILITY_ID
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.UnitId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"INSERT INTO UnitDescription
|
||||
(
|
||||
UnitId,
|
||||
Code,
|
||||
Name,
|
||||
Description
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@UNIT_ID,
|
||||
@CODE,
|
||||
@NAME,
|
||||
@DESCRIPTION
|
||||
)";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
UNIT_ID = input.UnitId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
DESCRIPTION = description.Description
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Unit input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "DELETE FROM Units WHERE UnitId = @UNIT_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
UNIT_ID = input.UnitId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task DeleteUnitAsync(int userId, int unitId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "DELETE FROM UserUnits WHERE UserId = @USER_ID AND UnitId = @UNIT_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
USER_ID = userId,
|
||||
UNIT_ID = unitId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Unit?> GetAsync(int unitId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT * FROM Units WHERE UnitId = @UNIT_ID";
|
||||
|
||||
var unit = await dbController.GetFirstAsync<Unit>(sql, new
|
||||
{
|
||||
UNIT_ID = unitId
|
||||
}, cancellationToken);
|
||||
|
||||
if (unit?.PrimaryWeaponId != null && unit?.SecondaryWeaponId != null)
|
||||
{
|
||||
unit.PrimaryWeapon = await _weaponService.GetAsync((int)unit.PrimaryWeaponId, dbController, cancellationToken) ?? new();
|
||||
unit.SecondaryWeapon = await _weaponService.GetAsync((int)unit.SecondaryWeaponId, dbController, cancellationToken) ?? new();
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
public static async Task<List<Unit>> GetAllAsync(IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "SELECT * FROM Units";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Unit>(sql, cancellationToken: cancellationToken);
|
||||
|
||||
await LoadUnitDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<List<Unit>> GetAsync(UnitFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT ud.Name, u.* " +
|
||||
"FROM UnitDescription ud " +
|
||||
"INNER JOIN Units u " +
|
||||
"ON (u.UnitId = ud.UnitId) " +
|
||||
"WHERE 1 = 1");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
sqlBuilder.AppendLine(@$" ORDER BY Name ASC ");
|
||||
sqlBuilder.AppendLine(dbController.GetPaginationSyntax(filter.PageNumber, filter.Limit));
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
List<Unit> list = await dbController.SelectDataAsync<Unit>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
await LoadUnitDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetFilterParameter(UnitFilter filter)
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SEARCHPHRASE", $"%{filter.SearchPhrase}%" },
|
||||
{ "FRACTION_ID", filter.FractionId },
|
||||
{ "CULTURE", CultureInfo.CurrentCulture.Name }
|
||||
};
|
||||
}
|
||||
|
||||
public string GetFilterWhere(UnitFilter filter)
|
||||
{
|
||||
StringBuilder sqlBuilder = new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchPhrase))
|
||||
{
|
||||
sqlBuilder.AppendLine(@" AND (UPPER(Name) LIKE @SEARCHPHRASE)");
|
||||
}
|
||||
if (filter.FractionId != 0)
|
||||
{
|
||||
sqlBuilder.AppendLine(@" AND FractionId = @FRACTION_ID");
|
||||
}
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalAsync(UnitFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT COUNT(*) AS record_count FROM UnitDescription ud JOIN Units u ON ud.UnitId = u.UnitId WHERE 1 = 1");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
int result = await dbController.GetFirstAsync<int>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<List<Unit>> GetUserUnitsAsync(int userId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"
|
||||
SELECT uu.Quantity, u.*
|
||||
FROM UserUnits uu
|
||||
INNER JOIN Units u ON (u.UnitId = uu.UnitId)
|
||||
WHERE uu.UserId = @USER_ID";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Unit>(sql, new
|
||||
{
|
||||
USER_ID = userId
|
||||
}, cancellationToken);
|
||||
|
||||
await LoadUnitDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<List<Unit>> GetPlayerUnitsAsync(int playerId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"
|
||||
SELECT pu.Quantity, u.*
|
||||
FROM PlayerUnits pu
|
||||
INNER JOIN Units u ON (u.UnitId = pu.UnitId)
|
||||
WHERE pu.PlayerId = @PLAYER_ID";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Unit>(sql, new
|
||||
{
|
||||
PLAYER_ID = playerId
|
||||
}, cancellationToken);
|
||||
|
||||
await LoadUnitDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static async Task<List<Unit>> GetTemplateUnitsAsync(int templateId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"
|
||||
SELECT tu.Quantity, u.*
|
||||
FROM TemplateUnits tu
|
||||
INNER JOIN Units u ON (u.UnitId = tu.UnitId)
|
||||
WHERE tu.TemplateId = @TEMPLATE_ID";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Unit>(sql, new
|
||||
{
|
||||
TEMPLATE_ID = templateId
|
||||
}, cancellationToken);
|
||||
|
||||
await LoadUnitDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task CreateUserUnitAsync(User user, Unit unit, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "DELETE FROM UserUnits WHERE UserId = @USER_ID AND UnitId = @UNIT_ID";
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
USER_ID = user.UserId,
|
||||
UNIT_ID = unit.UnitId
|
||||
}, cancellationToken);
|
||||
|
||||
sql = @"INSERT INTO UserUnits
|
||||
(
|
||||
UserId,
|
||||
UnitId,
|
||||
Quantity
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@USER_ID,
|
||||
@UNIT_ID,
|
||||
@QUANTITY
|
||||
)";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
USER_ID = user.UserId,
|
||||
UNIT_ID = unit.UnitId,
|
||||
QUANTITY = unit.Quantity
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task DeleteTemplateUnitsAsync(int templateId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "DELETE FROM TemplateUnits WHERE TemplateId = @TEMPLATE_ID";
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
TEMPLATE_ID = templateId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task DeletePlayerUnitsAsync(int playerid, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = "DELETE FROM PlayerUnits WHERE PlayerId = @PLAYER_ID";
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
PLAYER_ID = playerid
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task CreateTemplateUnitAsync(int templateId, Unit unit, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"INSERT INTO TemplateUnits
|
||||
(
|
||||
TemplateId,
|
||||
UnitId,
|
||||
Quantity
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@TEMPLATE_ID,
|
||||
@UNIT_ID,
|
||||
@QUANTITY
|
||||
)";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
TEMPLATE_ID = templateId,
|
||||
UNIT_ID = unit.UnitId,
|
||||
QUANTITY = unit.Quantity
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task CreatePlayerUnitAsync(Player Input, Unit unit, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"INSERT INTO PlayerUnits
|
||||
(
|
||||
PlayerId,
|
||||
UnitId,
|
||||
Quantity
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@PLAYER_ID,
|
||||
@UNIT_ID,
|
||||
@QUANTITY
|
||||
)";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
PLAYER_ID = Input.PlayerId,
|
||||
UNIT_ID = unit.UnitId,
|
||||
QUANTITY = unit.Quantity
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Unit input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string sql = @"UPDATE Units SET
|
||||
FractionId = @FRACTION_ID,
|
||||
ClassId = @CLASS_ID,
|
||||
TroopQuantity = @TROOP_QUANTITY,
|
||||
Defense = @DEFENSE,
|
||||
Moving = @MOVING,
|
||||
PrimaryWeaponId = @PRIMARY_WEAPON_ID,
|
||||
SecondaryWeaponId = @SECONDARY_WEAPON_ID,
|
||||
FirstAbilityId = @FIRST_ABILITY_ID,
|
||||
SecondAbilityId = @SECOND_ABILITY_ID
|
||||
WHERE UnitId = @UNIT_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"UPDATE UnitDescription SET
|
||||
Name = @NAME,
|
||||
Description = @DESCRIPTION,
|
||||
Mechanic = @MECHANIC
|
||||
WHERE UnitId = @UNIT_ID AND Code = @CODE";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
UNIT_ID = input.UnitId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
DESCRIPTION = description.Description,
|
||||
MECHANIC = description.Mechanic
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task LoadUnitDescriptionsAsync(List<Unit> list, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
IEnumerable<int> unitIds = list.Select(x => x.UnitId);
|
||||
string sql = $"SELECT * FROM UnitDescription WHERE UnitId IN ({string.Join(",", unitIds)})";
|
||||
List<UnitDescription> descriptions = await dbController.SelectDataAsync<UnitDescription>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var unit in list)
|
||||
{
|
||||
unit.Description = [.. descriptions.Where(x => x.UnitId == unit.UnitId)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
298
Tabletop.Core/Services/UserService.cs
Normal file
298
Tabletop.Core/Services/UserService.cs
Normal file
@@ -0,0 +1,298 @@
|
||||
using DbController;
|
||||
using System.Text;
|
||||
using Tabletop.Core.Filters;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class UserService(PermissionService permissionService) : IModelService<User, int, UserFilter>
|
||||
{
|
||||
private readonly PermissionService _permissionService = permissionService;
|
||||
|
||||
public async Task CreateAsync(User input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
input.LastLogin = DateTime.Now;
|
||||
input.RegistrationDate = DateTime.Now;
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = $@"INSERT INTO Users
|
||||
(
|
||||
Username,
|
||||
DisplayName,
|
||||
Password,
|
||||
Salt,
|
||||
LastLogin,
|
||||
RegistrationDate
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@USERNAME,
|
||||
@DISPLAY_NAME,
|
||||
@PASSWORD,
|
||||
@SALT,
|
||||
@LAST_LOGIN,
|
||||
@REGISTRATION_DATE
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.UserId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
await _permissionService.UpdateUserPermissionsAsync(input, dbController, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(User input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "DELETE FROM Users WHERE UserId = @USER_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
USER_ID = input.UserId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task DeleteFriendAsync(int userId, int friendId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "DELETE FROM UserFriends WHERE UserId = @USER_ID AND FriendId = @FRIEND_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
USER_ID = userId,
|
||||
FRIEND_ID = friendId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<User?> GetAsync(int userId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT * FROM Users WHERE UserId = @USER_ID";
|
||||
|
||||
var user = await dbController.GetFirstAsync<User>(sql, new
|
||||
{
|
||||
USER_ID = userId
|
||||
}, cancellationToken);
|
||||
|
||||
if (user is not null)
|
||||
{
|
||||
user.Permissions = await PermissionService.GetUserPermissionsAsync(user.UserId, dbController, cancellationToken);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async Task<User?> GetAsync(string username, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT * FROM Users WHERE UPPER(username) = UPPER(@USERNAME)";
|
||||
|
||||
var user = await dbController.GetFirstAsync<User>(sql, new
|
||||
{
|
||||
USERNAME = username
|
||||
}, cancellationToken);
|
||||
|
||||
if (user is not null)
|
||||
{
|
||||
user.Permissions = await PermissionService.GetUserPermissionsAsync(user.UserId, dbController, cancellationToken);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public async Task<User?> GetUserInformationAsync(int userId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT UserId, Username, DisplayName, Image FROM Users WHERE UserId = @USER_ID";
|
||||
|
||||
var user = await dbController.GetFirstAsync<User>(sql, new
|
||||
{
|
||||
USER_ID = userId
|
||||
}, cancellationToken);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public async Task<List<User>> GetAsync(UserFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.Append("SELECT UserId, Username, DisplayName, Description, MainFractionId, LastLogin, RegistrationDate, Image FROM Users WHERE 1 = 1");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@$" ORDER BY UserId DESC");
|
||||
sqlBuilder.AppendLine(dbController.GetPaginationSyntax(filter.PageNumber, filter.Limit));
|
||||
|
||||
// Zum Debuggen schreiben wir den Wert einmal als Variabel
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
List<User> list = await dbController.SelectDataAsync<User>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
// Berechtigungen müssen noch geladen werden
|
||||
List<Permission> permissions = await PermissionService.GetAllAsync(dbController);
|
||||
|
||||
sql = "SELECT * FROM UserPermissions";
|
||||
List<UserPermission> user_permissions = await dbController.SelectDataAsync<UserPermission>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var user in list)
|
||||
{
|
||||
List<UserPermission> permissions_for_user = [.. user_permissions.Where(x => x.UserId == user.UserId)];
|
||||
List<int> permission_ids = [.. permissions_for_user.Select(x => x.PermissionId)];
|
||||
|
||||
user.Permissions = [.. permissions.Where(x => permission_ids.Contains(x.PermissionId))];
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetFilterParameter(UserFilter filter)
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SEARCHPHRASE", $"%{filter.SearchPhrase}%" }
|
||||
};
|
||||
}
|
||||
|
||||
public string GetFilterWhere(UserFilter filter)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchPhrase))
|
||||
{
|
||||
sb.AppendLine(@" AND
|
||||
(
|
||||
UPPER(DisplayName) LIKE @SEARCHPHRASE
|
||||
OR UPPER(Username) LIKE @SEARCHPHRASE
|
||||
)");
|
||||
}
|
||||
|
||||
string sql = sb.ToString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalAsync(UserFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT COUNT(*) FROM Users WHERE 1 = 1");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
int result = await dbController.GetFirstAsync<int>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<List<User>> GetUserFriendsAsync(int userId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT u.UserId, u.Username, u.DisplayName, u.Image
|
||||
FROM Users AS u
|
||||
JOIN UserFriends AS uf ON u.UserId = uf.FriendId
|
||||
WHERE uf.UserId = @USER_ID";
|
||||
|
||||
var list = await dbController.SelectDataAsync<User>(sql, new
|
||||
{
|
||||
USER_ID = userId
|
||||
}, cancellationToken);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static async Task<bool> CheckUserFriendAsync(int userId, int friendId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM UserFriends
|
||||
WHERE UserId = @USER_ID AND FriendId = @FRIEND_ID
|
||||
) THEN 'true'
|
||||
ELSE 'false'
|
||||
END AS IsFriend;";
|
||||
|
||||
bool isfriend = await dbController.GetFirstAsync<bool>(sql, new
|
||||
{
|
||||
USER_ID = userId,
|
||||
FRIEND_ID = friendId
|
||||
}, cancellationToken);
|
||||
|
||||
return isfriend;
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(User input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"UPDATE Users SET
|
||||
Username = @USERNAME,
|
||||
DisplayName = @DISPLAY_NAME,
|
||||
Description = @DESCRIPTION,
|
||||
MainFractionId = @MAIN_FRACTION_ID
|
||||
WHERE UserId = @USER_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
await _permissionService.UpdateUserPermissionsAsync(input, dbController, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task UpdateLastLoginAsync(User input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
input.LastLogin = DateTime.Now;
|
||||
string sql = @"UPDATE Users SET
|
||||
LastLogin = @LAST_LOGIN
|
||||
WHERE UserId = @USER_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task<bool> FirstUserExistsAsync(IDbController dbController)
|
||||
{
|
||||
string sql = "SELECT * FROM Users";
|
||||
|
||||
var tmp = await dbController.GetFirstAsync<object>(sql);
|
||||
|
||||
return tmp != null;
|
||||
}
|
||||
|
||||
public async Task<string> GetUsernameAsync(int userId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT Username FROM Users WHERE UserId = @USER_ID";
|
||||
|
||||
var user = await dbController.GetFirstAsync<User>(sql, new
|
||||
{
|
||||
USER_ID = userId
|
||||
}, cancellationToken);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
return user.Username;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task CreateUserFriendAsync(int userId, int friendId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"INSERT INTO UserFriends
|
||||
(
|
||||
UserId,
|
||||
FriendId
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@USER_ID,
|
||||
@FRIEND_ID
|
||||
)";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
USER_ID = userId,
|
||||
FRIEND_ID = friendId
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
215
Tabletop.Core/Services/WeaponService.cs
Normal file
215
Tabletop.Core/Services/WeaponService.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using DbController;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Tabletop.Core.Filters;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Services
|
||||
{
|
||||
public class WeaponService : IModelService<Weapon, int, WeaponFilter>
|
||||
{
|
||||
public async Task CreateAsync(Weapon input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = $@"INSERT INTO Weapons
|
||||
(
|
||||
Attack,
|
||||
Quality,
|
||||
Range,
|
||||
Dices
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@ATTACK,
|
||||
@QUALITY,
|
||||
@RANGE,
|
||||
@DICES
|
||||
); {dbController.GetLastIdSql()}";
|
||||
|
||||
input.WeaponId = await dbController.GetFirstAsync<int>(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"INSERT INTO WeaponDescription
|
||||
(
|
||||
WeaponId,
|
||||
Code,
|
||||
Name,
|
||||
Description
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@WEAPON_ID,
|
||||
@CODE,
|
||||
@NAME,
|
||||
@DESCRIPTION
|
||||
)";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
WEAPON_ID = input.WeaponId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
DESCRIPTION = description.Description
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Weapon input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = "DELETE FROM Weapons WHERE WeaponId = @WEAPON_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, new
|
||||
{
|
||||
WEAPON_ID = input.WeaponId
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Weapon?> GetAsync(int weaponId, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"SELECT * FROM Weapons WHERE WeaponId = @WEAPON_ID";
|
||||
|
||||
var weapon = await dbController.GetFirstAsync<Weapon>(sql, new
|
||||
{
|
||||
WEAPON_ID = weaponId
|
||||
}, cancellationToken);
|
||||
|
||||
if(weapon != null)
|
||||
{
|
||||
await LoadWeaponDescriptionAsync(weapon, dbController, cancellationToken);
|
||||
}
|
||||
return weapon;
|
||||
}
|
||||
|
||||
public async Task<List<Weapon>> GetAsync(WeaponFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT wd.Name, w.* " +
|
||||
"FROM WeaponDescription wd " +
|
||||
"INNER JOIN Weapons w " +
|
||||
"ON (w.WeaponId = wd.WeaponId) " +
|
||||
"WHERE 1 = 1");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
sqlBuilder.AppendLine(@$" ORDER BY Name ASC ");
|
||||
sqlBuilder.AppendLine(dbController.GetPaginationSyntax(filter.PageNumber, filter.Limit));
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
List<Weapon> list = await dbController.SelectDataAsync<Weapon>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
await LoadWeaponDescriptionsAsync(list, dbController, cancellationToken);
|
||||
return list;
|
||||
}
|
||||
|
||||
public Dictionary<string, object?> GetFilterParameter(WeaponFilter filter)
|
||||
{
|
||||
return new Dictionary<string, object?>
|
||||
{
|
||||
{ "SEARCHPHRASE", $"%{filter.SearchPhrase}%" },
|
||||
{ "CULTURE", CultureInfo.CurrentCulture.Name }
|
||||
};
|
||||
}
|
||||
|
||||
public string GetFilterWhere(WeaponFilter filter)
|
||||
{
|
||||
StringBuilder sqlBuilder = new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchPhrase))
|
||||
{
|
||||
sqlBuilder.AppendLine(@" AND (UPPER(Name) LIKE @SEARCHPHRASE)");
|
||||
}
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalAsync(WeaponFilter filter, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
StringBuilder sqlBuilder = new();
|
||||
sqlBuilder.AppendLine("SELECT COUNT(*) AS record_count FROM WeaponDescription WHERE 1 = 1 ");
|
||||
sqlBuilder.AppendLine(GetFilterWhere(filter));
|
||||
sqlBuilder.AppendLine(@" AND Code = @CULTURE");
|
||||
|
||||
string sql = sqlBuilder.ToString();
|
||||
|
||||
int result = await dbController.GetFirstAsync<int>(sql, GetFilterParameter(filter), cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<List<Weapon>> GetAllAsync(IDbController dbController)
|
||||
{
|
||||
string sql = "SELECT * FROM Weapons";
|
||||
|
||||
var list = await dbController.SelectDataAsync<Weapon>(sql);
|
||||
await LoadWeaponDescriptionsAsync(list, dbController);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Weapon input, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string sql = @"UPDATE Weapons SET
|
||||
Attack = @ATTACK,
|
||||
Quality = @QUALITY,
|
||||
Range = @RANGE,
|
||||
Dices = @DICES
|
||||
WHERE WeaponId = @WEAPON_ID";
|
||||
|
||||
await dbController.QueryAsync(sql, input.GetParameters(), cancellationToken);
|
||||
|
||||
foreach (var description in input.Description)
|
||||
{
|
||||
sql = @"UPDATE WeaponDescription SET
|
||||
Name = @NAME,
|
||||
Description = @DESCRIPTION
|
||||
WHERE WeaponId = @WEAPON_ID AND Code = @CODE";
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
WEAPON_ID = input.WeaponId,
|
||||
CODE = description.Code,
|
||||
NAME = description.Name,
|
||||
DESCRIPTION = description.Description
|
||||
};
|
||||
|
||||
await dbController.QueryAsync(sql, parameters, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task LoadWeaponDescriptionsAsync(List<Weapon> list, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
IEnumerable<int> weaponIds = list.Select(x => x.WeaponId);
|
||||
string sql = $"SELECT * FROM WeaponDescription WHERE WeaponId IN ({string.Join(",", weaponIds)})";
|
||||
List<WeaponDescription> descriptions = await dbController.SelectDataAsync<WeaponDescription>(sql, null, cancellationToken);
|
||||
|
||||
foreach (var weapon in list)
|
||||
{
|
||||
weapon.Description = descriptions.Where(x => x.WeaponId == weapon.WeaponId).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task LoadWeaponDescriptionAsync(Weapon weapon, IDbController dbController, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
|
||||
string sql = $"SELECT * FROM WeaponDescription WHERE WeaponId IN @WEAPON_ID";
|
||||
weapon.Description = await dbController.SelectDataAsync<WeaponDescription>(sql, new
|
||||
{
|
||||
WEAPON_ID = weapon.WeaponId
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Tabletop.Core/Tabletop.Core.csproj
Normal file
39
Tabletop.Core/Tabletop.Core.csproj
Normal file
@@ -0,0 +1,39 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Pages\**" />
|
||||
<EmbeddedResource Remove="Pages\**" />
|
||||
<None Remove="Pages\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DbController" Version="5.0.0" />
|
||||
<PackageReference Include="DbController.SqlServer" Version="5.0.0" />
|
||||
<PackageReference Include="DbController.TypeHandler" Version="5.0.0" />
|
||||
<PackageReference Include="FluentValidation" Version="12.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.3.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="System.Security.Cryptography.Xml" Version="10.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
26
Tabletop.Core/Validators/AbilityValidator.cs
Normal file
26
Tabletop.Core/Validators/AbilityValidator.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using FluentValidation;
|
||||
using System.Globalization;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Validators
|
||||
{
|
||||
public class AbilityValidator : AbstractValidator<Ability>
|
||||
{
|
||||
public AbilityValidator()
|
||||
{
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Name)
|
||||
.NotEmpty()
|
||||
.WithMessage("The field must be filled")
|
||||
.MaximumLength(50)
|
||||
.WithMessage("Name must contain only 50 characters.");
|
||||
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Description)
|
||||
.MaximumLength(1000)
|
||||
.WithMessage("Description must contain only 1000 characters.");
|
||||
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Mechanic)
|
||||
.MaximumLength(1000)
|
||||
.WithMessage("Mechanic must contain only 1000 characters.");
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Tabletop.Core/Validators/FractionValidator.cs
Normal file
28
Tabletop.Core/Validators/FractionValidator.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using FluentValidation;
|
||||
using System.Globalization;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Validators
|
||||
{
|
||||
public class FractionValidator : AbstractValidator<Fraction>
|
||||
{
|
||||
public FractionValidator()
|
||||
{
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Name)
|
||||
.NotEmpty()
|
||||
.WithMessage("The field must be filled")
|
||||
.MaximumLength(50)
|
||||
.WithMessage("Name must contain only 50 characters.");
|
||||
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).ShortName)
|
||||
.NotEmpty()
|
||||
.WithMessage("The field must be filled")
|
||||
.MaximumLength(3)
|
||||
.WithMessage("Name must contain only 3 characters.");
|
||||
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Description)
|
||||
.MaximumLength(1000)
|
||||
.WithMessage("Description must contain only 1000 characters.");
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Tabletop.Core/Validators/GameValidator.cs
Normal file
32
Tabletop.Core/Validators/GameValidator.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using FluentValidation;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Validators
|
||||
{
|
||||
public class GameValidator : AbstractValidator<Game>
|
||||
{
|
||||
public GameValidator()
|
||||
{
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty()
|
||||
.WithMessage("The field must be filled")
|
||||
.MaximumLength(30)
|
||||
.WithMessage("Name must contain only 30 characters.");
|
||||
|
||||
RuleFor(x => x.GamemodeId)
|
||||
.NotEmpty()
|
||||
.WithMessage("Game Mode must be selected");
|
||||
|
||||
When(x => x.GamemodeId is 1 or 4, () =>
|
||||
{
|
||||
RuleFor(x => x.NumberOfRounds)
|
||||
.NotNull()
|
||||
.WithMessage("Rounds must be selected");
|
||||
});
|
||||
|
||||
RuleFor(x => x.Force)
|
||||
.NotEmpty()
|
||||
.WithMessage("Force must be selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Tabletop.Core/Validators/GamemodeValidator.cs
Normal file
26
Tabletop.Core/Validators/GamemodeValidator.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using FluentValidation;
|
||||
using System.Globalization;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Validators
|
||||
{
|
||||
public class GamemodeValidator : AbstractValidator<Gamemode>
|
||||
{
|
||||
public GamemodeValidator()
|
||||
{
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Name)
|
||||
.NotEmpty()
|
||||
.WithMessage("The field must be filled")
|
||||
.MaximumLength(50)
|
||||
.WithMessage("Name must contain only 50 characters.");
|
||||
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Description)
|
||||
.MaximumLength(1000)
|
||||
.WithMessage("Description must contain only 1000 characters.");
|
||||
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Mechanic)
|
||||
.MaximumLength(1000)
|
||||
.WithMessage("Description must contain only 1000 characters.");
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Tabletop.Core/Validators/PlayerValidator.cs
Normal file
19
Tabletop.Core/Validators/PlayerValidator.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using FluentValidation;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Validators
|
||||
{
|
||||
public class PlayerValidator : AbstractValidator<Player>
|
||||
{
|
||||
public PlayerValidator()
|
||||
{
|
||||
RuleFor(x => x.UsedForce)
|
||||
.LessThanOrEqualTo(x => x.AllowedForce)
|
||||
.WithMessage("Force points over limit");
|
||||
|
||||
RuleFor(x => x.Units)
|
||||
.NotEmpty()
|
||||
.WithMessage("At least one unit must be selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Tabletop.Core/Validators/TemplateValidator.cs
Normal file
29
Tabletop.Core/Validators/TemplateValidator.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using FluentValidation;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Validators
|
||||
{
|
||||
public class TemplateValidator : AbstractValidator<Template>
|
||||
{
|
||||
public TemplateValidator()
|
||||
{
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty()
|
||||
.WithMessage("The field must be filled")
|
||||
.MaximumLength(50)
|
||||
.WithMessage("Name must contain only 50 characters.");
|
||||
|
||||
RuleFor(x => x.FractionId)
|
||||
.NotEmpty()
|
||||
.WithMessage("Faction must be selected");
|
||||
|
||||
RuleFor(x => x.Force)
|
||||
.NotEmpty()
|
||||
.WithMessage("Force must be selected");
|
||||
|
||||
RuleFor(x => x.UsedForce)
|
||||
.LessThanOrEqualTo(x => x.Force)
|
||||
.WithMessage("Force points over limit");
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Tabletop.Core/Validators/UnitValidator.cs
Normal file
42
Tabletop.Core/Validators/UnitValidator.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using FluentValidation;
|
||||
using System.Globalization;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Validators
|
||||
{
|
||||
public class UnitValidator : AbstractValidator<Unit>
|
||||
{
|
||||
public UnitValidator()
|
||||
{
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Name)
|
||||
.NotEmpty()
|
||||
.WithMessage("The field must be filled")
|
||||
.MaximumLength(50)
|
||||
.WithMessage("Name must contain only 50 characters.");
|
||||
|
||||
RuleFor(x => x.FractionId)
|
||||
.NotEmpty()
|
||||
.WithMessage("Faction must be selected");
|
||||
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Description)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("Description must contain only 500 characters.");
|
||||
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Mechanic)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("Description must contain only 500 characters.");
|
||||
|
||||
RuleFor(x => x.Defense)
|
||||
.NotEmpty()
|
||||
.WithMessage("Defense must be filled.");
|
||||
|
||||
RuleFor(x => x.Moving)
|
||||
.NotEmpty()
|
||||
.WithMessage("The field must be filled")
|
||||
.LessThan(30)
|
||||
.WithMessage("The field may be a maximum of 30")
|
||||
.GreaterThan(0)
|
||||
.WithMessage("The field must not be greater than 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Tabletop.Core/Validators/WeaponValidator.cs
Normal file
38
Tabletop.Core/Validators/WeaponValidator.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using FluentValidation;
|
||||
using System.Globalization;
|
||||
using Tabletop.Core.Models;
|
||||
|
||||
namespace Tabletop.Core.Validators
|
||||
{
|
||||
public class WeaponValidator : AbstractValidator<Weapon>
|
||||
{
|
||||
public WeaponValidator()
|
||||
{
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Name)
|
||||
.NotEmpty()
|
||||
.WithMessage("The field must be filled")
|
||||
.MaximumLength(50)
|
||||
.WithMessage("Name must contain only 50 characters.");
|
||||
|
||||
RuleFor(x => x.GetLocalization(CultureInfo.CurrentCulture).Description)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("Description must contain only 500 characters.");
|
||||
|
||||
RuleFor(x => x.Attack)
|
||||
.NotEmpty()
|
||||
.WithMessage("Attack must be filled.");
|
||||
|
||||
RuleFor(x => x.Quality)
|
||||
.NotEmpty()
|
||||
.WithMessage("Quality must be filled");
|
||||
|
||||
RuleFor(x => x.Range)
|
||||
.NotEmpty()
|
||||
.WithMessage("Range must be filled");
|
||||
|
||||
RuleFor(x => x.Dices)
|
||||
.NotEmpty()
|
||||
.WithMessage("Dices must be filled");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tabletop.Core/appsettings.json
Normal file
11
Tabletop.Core/appsettings.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"Filter": {
|
||||
"PageLimit": 30
|
||||
},
|
||||
"Sql": {
|
||||
"ConnectionString": "Server=localhost\\SQLEXPRESS;Database=Tabletop;Trusted_Connection=True;TrustServerCertificate=True;"
|
||||
},
|
||||
"IpGeolocation": {
|
||||
"ApiKey": "43d1738db9eb411cb959972585b331f6"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user