Merge branch 'master' of ssh://float.ownsoft.de/git/beyondSoft/BeWo

This commit is contained in:
2026-04-14 08:53:24 +02:00
12 changed files with 462 additions and 0 deletions

View File

@@ -91,6 +91,8 @@ namespace BS.Shared.Core.Rule
public static bool IsUnitDescriptionValid(IInvoiceItem invoiceItem)
{
if(invoiceItem == null) return false;
// GPos. 123456
// 0123456
return invoiceItem.UnitDescription.Length >= 8;

View File

@@ -0,0 +1,22 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35707.178 d17.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeWoLogCleaner", "BeWoLogCleaner\BeWoLogCleaner.csproj", "{319D754B-02E6-46B9-8C3B-EEA6613584A6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{319D754B-02E6-46B9-8C3B-EEA6613584A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{319D754B-02E6-46B9-8C3B-EEA6613584A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{319D754B-02E6-46B9-8C3B-EEA6613584A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{319D754B-02E6-46B9-8C3B-EEA6613584A6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net debug="true">
<root>
<level value="INFO" />
<appender-ref ref="logFile" />
<appender-ref ref="console" />
</root>
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %logger - %message%newline" />
</layout>
</appender>
<appender name="logFile" type="log4net.Appender.RollingFileAppender,log4net">
<param name="LockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="File" value="logs\log_" />
<param name="AppendToFile" value="true" />
<param name="RollingStyle" value="Composite" />
<param name="DatePattern" value="yyyy.MM.dd'.log'" />
<param name="StaticLogFileName" value="false" />
<param name="MaxSizeRollBackups" value="0" />
<param name="MaximumFileSize" value="100MB" />
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
</log4net>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{319D754B-02E6-46B9-8C3B-EEA6613584A6}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>BeWoLogCleaner</RootNamespace>
<AssemblyName>BeWoLogCleaner</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net">
<HintPath>..\..\..\Lib\log4net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=10.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.5\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.IO.Pipelines, Version=10.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Pipelines.10.0.5\lib\net462\System.IO.Pipelines.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.6.3\lib\net462\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.1.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=10.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.10.0.5\lib\net462\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=10.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.10.0.5\lib\net462\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.4.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.6.3\lib\net462\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CleanerConfig.cs" />
<Compile Include="CleanRule.cs" />
<Compile Include="Enums.cs" />
<Compile Include="LoggerUtils.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="clean_config.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\System.ValueTuple.4.6.1\build\net471\System.ValueTuple.targets" Condition="Exists('..\packages\System.ValueTuple.4.6.1\build\net471\System.ValueTuple.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\System.ValueTuple.4.6.1\build\net471\System.ValueTuple.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.ValueTuple.4.6.1\build\net471\System.ValueTuple.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace BeWoLogCleaner
{
public class CleanRule
{
[JsonPropertyName("name")]
public string Name { get; set; } = "";
[JsonPropertyName("directory")]
public string Directory { get; set; } = "";
[JsonPropertyName("pattern")]
public string Pattern { get; set; } = "*.log";
[JsonPropertyName("recursive")]
public bool Recursive { get; set; } = false;
[JsonPropertyName("retentiondays")]
public int RetentionDays { get; set; } = 7;
[JsonPropertyName("action")]
public CleanAction Action { get; set; } = CleanAction.Delete;
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace BeWoLogCleaner
{
public class CleanerConfig
{
[JsonPropertyName("rules")]
public List<CleanRule> Rules { get; set; } = new List<CleanRule>();
[JsonPropertyName("dryrun")]
public bool DryRun { get; set; } = false;
}
}

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWoLogCleaner
{
public enum CleanAction
{ Delete, Compress }
}

View File

@@ -0,0 +1,30 @@
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWoLogCleaner
{
public static class LoggerUtils
{
private static bool _LoggerInit = false;
public static void InitLogger()
{
if (_LoggerInit) return;
log4net.Config.XmlConfigurator.Configure();
_LoggerInit = true;
}
public static ILog GetLogger(Type declaringType)
{
InitLogger();
return log4net.LogManager.GetLogger(declaringType);
}
}
}

View File

@@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
using log4net;
namespace BeWoLogCleaner
{
internal class Program
{
static ILog Logger { get; set; }
static CleanerConfig Config { get; set; }
static void Main(string[] args)
{
Logger = LoggerUtils.GetLogger(typeof(Program));
ReadConfig();
Run();
}
static void ReadConfig()
{
var path = "clean_config.json";
var json = File.ReadAllText(path);
var json_obj = JsonSerializer.Deserialize<CleanerConfig>(json);
Config = json_obj;
}
static void Run()
{
WriteLine("=== Log File Cleaner ===");
if (Config.DryRun)
WriteLine("*** DRY-RUN es werden keine Dateien verändert ***");
WriteLine();
int totalFiles = 0;
long totalBytes = 0;
foreach (var rule in Config.Rules)
{
WriteLine($"[{rule.Name}]");
WriteLine($" Verzeichnis : {rule.Directory}");
WriteLine($" Muster : {rule.Pattern}");
WriteLine($" Alter : > {rule.RetentionDays} Tage");
WriteLine($" Aktion : {rule.Action}");
WriteLine();
if (!Directory.Exists(rule.Directory))
{
WriteLine($" ⚠ Verzeichnis nicht gefunden, übersprungen.");
WriteLine();
continue;
}
var searchOption = rule.Recursive
? SearchOption.AllDirectories
: SearchOption.TopDirectoryOnly;
var files = Directory
.EnumerateFiles(rule.Directory, rule.Pattern, searchOption)
.Select(p => new FileInfo(p))
.Where(f => (DateTime.Now - f.LastWriteTime).TotalDays > rule.RetentionDays)
.ToList();
if (files.Count == 0)
{
WriteLine(" Keine Dateien gefunden.");
WriteLine();
continue;
}
foreach (var file in files)
{
long size = file.Length;
switch (rule.Action)
{
case CleanAction.Delete:
var str = $" 🗑 {file.FullName} ({FormatSize(size)})";
if (!Config.DryRun)
{
file.Delete();
totalBytes += size;
WriteLine(str + " → gelöscht");
}
else
{
WriteLine(str + " → [DRY-RUN]");
}
break;
case CleanAction.Compress:
var gzPath = file.FullName + ".gz";
var str1 = $" 📦 {file.FullName} ({FormatSize(size)})";
if (!Config.DryRun)
{
CompressFile(file, gzPath);
long saved = size - new FileInfo(gzPath).Length;
totalBytes += saved;
WriteLine($"{str1} → komprimiert (gespart: {FormatSize(saved)})");
}
else
{
WriteLine($"{str1} → [DRY-RUN]");
}
break;
}
totalFiles++;
}
WriteLine();
}
WriteLine("=== Zusammenfassung ===");
WriteLine($" Dateien verarbeitet : {totalFiles}");
WriteLine($" Speicher freigegeben: {FormatSize(totalBytes)}");
if (Config.DryRun)
WriteLine(" (DRY-RUN nichts wurde wirklich verändert)");
}
static void WriteLine(string line = "")
{
Console.WriteLine(line);
Logger.Info(line);
}
private static void CompressFile(FileInfo source, string destPath)
{
using (var input = source.OpenRead())
{
using (var output = File.Create(destPath))
{
using (var gz = new GZipStream(output, CompressionLevel.Optimal))
{
input.CopyTo(gz);
source.Delete();
}
}
}
}
private static string FormatSize(long bytes)
{
if (bytes < 1_024)
return $"{bytes} B";
if (bytes < 1_048_576)
return $"{bytes / 1024.0:F1} KB";
if (bytes < 1_073_741_824)
return $"{bytes / 1_048_576.0:F1} MB";
return $"{bytes / 1_073_741_824.0:F2} GB";
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("BeWoLogCleaner")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BeWoLogCleaner")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("319d754b-02e6-46b9-8c3b-eea6613584a6")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,12 @@
{
"dryrun": true,
"rules": [
{
"name": "ai_requests",
"directory": "C:\\Projects\\Bewo\\BeWo - Main\\Host\\logs\\LogFiles\\ai\\requests",
"recursive": false,
"retentiondays": 7,
"action": 0
}
]
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Bcl.AsyncInterfaces" version="10.0.5" targetFramework="net472" />
<package id="System.Buffers" version="4.6.1" targetFramework="net472" />
<package id="System.IO.Pipelines" version="10.0.5" targetFramework="net472" />
<package id="System.Memory" version="4.6.3" targetFramework="net472" />
<package id="System.Numerics.Vectors" version="4.6.1" targetFramework="net472" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.1.2" targetFramework="net472" />
<package id="System.Text.Encodings.Web" version="10.0.5" targetFramework="net472" />
<package id="System.Text.Json" version="10.0.5" targetFramework="net472" />
<package id="System.Threading.Tasks.Extensions" version="4.6.3" targetFramework="net472" />
<package id="System.ValueTuple" version="4.6.1" targetFramework="net472" />
</packages>