diff --git a/BeWo/BeWo.csproj b/BeWo/BeWo.csproj
index b91262adc..8bd750600 100644
--- a/BeWo/BeWo.csproj
+++ b/BeWo/BeWo.csproj
@@ -122,6 +122,7 @@
+
AiConfigView.xaml
diff --git a/BeWo/View/Detail/Accounting/InvoiceOverview.xaml.cs b/BeWo/View/Detail/Accounting/InvoiceOverview.xaml.cs
index 06b9f7c30..c6f677ce8 100644
--- a/BeWo/View/Detail/Accounting/InvoiceOverview.xaml.cs
+++ b/BeWo/View/Detail/Accounting/InvoiceOverview.xaml.cs
@@ -660,8 +660,6 @@ namespace BeWo.View.Detail.Accounting
x => x.CreateXRechnung(invoice_base_oid, invoice_type, report_link),
cb =>
{
-
-
if (cb is byte[] bytes)
{
File.WriteAllBytes(@"C:\Users\ownSoft\Desktop\XRechnung\test.pdf", bytes);
diff --git a/BeWo/ViewModel/InvoiceBaseVM.cs b/BeWo/ViewModel/InvoiceBaseVM.cs
index 5f82e70ef..3a6793cd6 100644
--- a/BeWo/ViewModel/InvoiceBaseVM.cs
+++ b/BeWo/ViewModel/InvoiceBaseVM.cs
@@ -923,6 +923,8 @@ namespace BeWo.ViewModel
public IList IInvoiceItems => throw new NotImplementedException();
+ public long? Oid => DataContract.InvoiceBaseOid;
+
protected override void InitByDataContract(InvoiceBaseDC pDataContract)
{
_SupportConceptOid = pDataContract.SupportConceptOid;
diff --git a/BeWo/ViewModel/StoredFileVM.cs b/BeWo/ViewModel/StoredFileVM.cs
new file mode 100644
index 000000000..c343d6751
--- /dev/null
+++ b/BeWo/ViewModel/StoredFileVM.cs
@@ -0,0 +1,89 @@
+using System;
+
+using BS.Shared;
+using BS.Shared.DataContracts;
+
+namespace BeWo.ViewModel
+{
+ public class StoredFileVM : AbstractDCMapperVM
+ {
+ private string _FileName;
+ private string _FilePath;
+ private string _ContentType;
+ private long _Size;
+ private string _Checksum;
+ private int? _BeWoObjectTid;
+ private long? _BeWoObjectOid;
+
+ public StoredFileVM(StoredFileDC dc) : base(dc, dc.Oid)
+ {
+
+ }
+
+ public string FileName
+ {
+ get => _FileName;
+ set => SetProperty(ref _FileName, value, nameof(FileName), () => DataContract.FileName);
+ }
+
+ public string FilePath
+ {
+ get => _FilePath;
+ set => SetProperty(ref _FilePath, value, nameof(FilePath), () => DataContract.FilePath);
+ }
+
+ public string ContentType
+ {
+ get => _ContentType;
+ set => SetProperty(ref _ContentType, value, nameof(ContentType), () => DataContract.ContentType);
+ }
+
+ public long Size
+ {
+ get => _Size;
+ set => SetProperty(ref _Size, value, nameof(Size), () => DataContract.Size);
+ }
+
+ public string Checksum
+ {
+ get => _Checksum;
+ set => SetProperty(ref _Checksum, value, nameof(Checksum), () => DataContract.Checksum);
+ }
+
+ public int? BeWoObjectTid
+ {
+ get => _BeWoObjectTid;
+ set => SetProperty(ref _BeWoObjectTid, value, nameof(BeWoObjectTid), () => DataContract.BeWoObjectTid);
+ }
+
+ public long? BeWoObjectOid
+ {
+ get => _BeWoObjectOid;
+ set => SetProperty(ref _BeWoObjectOid, value, nameof(BeWoObjectOid), () => DataContract.BeWoObjectOid);
+ }
+
+ protected override void InitByDataContract(StoredFileDC pDataContract)
+ {
+ _FileName = pDataContract.FileName;
+ _FilePath = pDataContract.FilePath;
+ _ContentType = pDataContract.ContentType;
+ _Size = pDataContract.Size;
+ _Checksum = pDataContract.Checksum;
+ _BeWoObjectTid = pDataContract.BeWoObjectTid;
+ _BeWoObjectOid = pDataContract.BeWoObjectOid;
+ }
+
+ protected override StoredFileDC MapToDataContract(StoredFileDC pDataContract, bool doCommit)
+ {
+ pDataContract.FileName = _FileName;
+ pDataContract.FilePath = _FilePath;
+ pDataContract.ContentType = _ContentType;
+ pDataContract.Size = _Size;
+ pDataContract.Checksum = _Checksum;
+ pDataContract.BeWoObjectTid = _BeWoObjectTid;
+ pDataContract.BeWoObjectOid = _BeWoObjectOid;
+
+ return pDataContract;
+ }
+ }
+}
diff --git a/Data/Access/DAOFactory.cs b/Data/Access/DAOFactory.cs
index 41749d635..791fd9a41 100644
--- a/Data/Access/DAOFactory.cs
+++ b/Data/Access/DAOFactory.cs
@@ -25,7 +25,7 @@ namespace BeWo.Data.Access
public static SearchDAO SearchDAO => _SearchDAO.Value;
public static UserDAO UserDAO => _UserDAO.Value;
- public static IFileStorageDAO GetLocalFileStorage(string rootpath)
+ public static LocalFileStorageDAO GetLocalFileStorage(string rootpath)
{
return new LocalFileStorageDAO(rootpath);
}
diff --git a/Data/Access/LocalFileStorageDAO.cs b/Data/Access/LocalFileStorageDAO.cs
index cb83fbf43..d94a5bcef 100644
--- a/Data/Access/LocalFileStorageDAO.cs
+++ b/Data/Access/LocalFileStorageDAO.cs
@@ -1,16 +1,21 @@
-using BS.Shared;
+using BeWo.Data.Entities;
+using BS.Shared;
+using BS.Shared.Core;
+using BS.Shared.Exceptions;
using BS.Shared.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Task = System.Threading.Tasks.Task;
namespace BeWo.Data.Access
{
- public class LocalFileStorageDAO : IFileStorageDAO
+ public class LocalFileStorageDAO
{
private readonly string _rootPath;
@@ -19,31 +24,69 @@ namespace BeWo.Data.Access
_rootPath = rootPath;
}
- private string GetFilePath(string customerId, BWPFeature feature, string fileName)
+ private string GetFilePath(string tenant, string filePath)
{
- return Path.Combine(_rootPath, customerId, feature.ToString(), fileName);
+ return Path.Combine(_rootPath, tenant, filePath);
}
- public async Task SaveFileAsync(string customerId, BWPFeature feature, string fileName, Stream content, CancellationToken cancellationToken = default)
+ public async Task SaveXRechnungPdfAsync(string tenant, IInvoiceBase invoicebase, Stream content)
{
- var path = GetFilePath(customerId, feature, fileName);
+ var lTid = (int)TableID.InvoiceBase;
+ var lOid = invoicebase.Oid;
+ var lFileName = $"{lOid}.XRechnung.pdf";
+
+ return await SaveFileAsync(tenant, BWPFeature.XRechnung, lFileName, "application/pdf", content, lTid, lOid).ConfigureAwait(true);
+ }
+
+ private async Task SaveFileAsync(string tenant, BWPFeature feature, string pFileName, string pContentType, Stream content, int? pBeWoObjectTid = null, long? pBeWoObjectOid = null, CancellationToken cancellationToken = default)
+ {
+ var lFilePath = feature.ToString();
+
+ return await SaveFileAsync(tenant, lFilePath, pFileName, pContentType, content, pBeWoObjectTid, pBeWoObjectOid, cancellationToken).ConfigureAwait(true);
+ }
+
+ private async Task SaveFileAsync(string tenant, string pFilePath, string pFileName, string pContentType, Stream content, int? pBeWoObjectTid = null, long? pBeWoObjectOid = null, CancellationToken cancellationToken = default)
+ {
+ // Prüfe Namen
+ if (SecurityUtils.ContainsInvalidFilenameChars(pFilePath))
+ throw new BeWoInvalidOperationException(AppError.LocalFileStorageFileNameInvalidChar);
+
+ if (Path.GetFileName(pFilePath) != pFileName)
+ throw new BeWoInvalidOperationException(AppError.LocalFileStorageFileNameNotEqFilePath);
+
+ // Erstelle DB Eintrag
+ var storedfile = new StoredFile();
+
+ storedfile.FileName = pFileName;
+ storedfile.FilePath = pFilePath;
+ storedfile.ContentType = pContentType;
+ storedfile.BeWoObjectTid = pBeWoObjectTid;
+ storedfile.BeWoObjectOid = pBeWoObjectOid;
+
+ // Erstelle File Ordner
+ var path = GetFilePath(tenant, pFilePath);
var directory = Path.GetDirectoryName(path);
Directory.CreateDirectory(directory);
+ // Speichere Datei
using (var stream = File.Create(path))
{
- await content.CopyToAsync(stream, bufferSize: 81920, cancellationToken).ConfigureAwait(true);
- };
+ await content.CopyToAsync(stream, bufferSize: 81920, cancellationToken).ConfigureAwait(true);
+ storedfile.Size = content.Position;
+ storedfile.Checksum = SecurityUtils.GetChecksumBuffered(content);
+ }
+
+ return storedfile;
}
- public Task FileExistsAsync(string customerId, BWPFeature feature, string fileName, CancellationToken cancellationToken = default)
+ public Task FileExistsAsync(string tenant, IStoredFile storedFile, CancellationToken cancellationToken = default)
{
- return Task.FromResult(File.Exists(GetFilePath(customerId, feature, fileName)));
+ return Task.FromResult(File.Exists(GetFilePath(tenant, storedFile.FilePath)));
}
- public Task GetFileAsync(string customerId, BWPFeature feature, string fileName, CancellationToken cancellationToken = default)
+ public Task GetFileAsync(string tenant, IStoredFile storedFile, CancellationToken cancellationToken = default)
{
- var path = GetFilePath(customerId, feature, fileName);
+ var path = GetFilePath(tenant, storedFile.FilePath);
if (!File.Exists(path))
return Task.FromResult(null);
@@ -51,9 +94,9 @@ namespace BeWo.Data.Access
return Task.FromResult(stream);
}
- public Task DeleteFileAsync(string customerId, BWPFeature feature, string fileName, CancellationToken cancellationToken = default)
+ public Task DeleteFileAsync(string tenant, IStoredFile storedFile, CancellationToken cancellationToken = default)
{
- var path = GetFilePath(customerId, feature, fileName);
+ var path = GetFilePath(tenant, storedFile.FilePath);
if (File.Exists(path))
{
File.Delete(path);
diff --git a/Data/Data.csproj b/Data/Data.csproj
index 9cb616c4e..631c319d2 100644
--- a/Data/Data.csproj
+++ b/Data/Data.csproj
@@ -236,6 +236,7 @@
+
@@ -830,6 +831,7 @@
+
Designer
diff --git a/Data/Entities/StoredFile.cs b/Data/Entities/StoredFile.cs
new file mode 100644
index 000000000..9a2a515e7
--- /dev/null
+++ b/Data/Entities/StoredFile.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+
+using BS.Shared;
+using BS.Shared.Core;
+using BS.Shared.Interface;
+
+namespace BeWo.Data.Entities
+{
+ public class StoredFile : BeWoEntityBase, IStoredFile
+ {
+ public StoredFile()
+ {
+ _Tid = TableID.StoredFile;
+ }
+
+ public virtual string FileName { get; set; }
+
+ public virtual string FilePath { get; set; }
+
+ public virtual string ContentType { get; set; }
+
+ public virtual long Size { get; set; }
+
+ public virtual string Checksum { get; set; }
+
+ public virtual int? BeWoObjectTid { get; set; }
+
+ public virtual long? BeWoObjectOid { get; set; }
+ }
+}
diff --git a/Data/Mappings/StoredFile.hbm.xml b/Data/Mappings/StoredFile.hbm.xml
new file mode 100644
index 000000000..2c7b52663
--- /dev/null
+++ b/Data/Mappings/StoredFile.hbm.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Host/Download.aspx.cs b/Host/Download.aspx.cs
index 43e3df83f..76feb4cb7 100644
--- a/Host/Download.aspx.cs
+++ b/Host/Download.aspx.cs
@@ -7,6 +7,7 @@ using BeWo.Data;
using BS.Shared.Core;
using BeWo.Service.Security;
+using SecurityUtils = BeWo.Service.Security.SecurityUtils;
public partial class Download : Page
{
diff --git a/Host/Host.csproj.user b/Host/Host.csproj.user
index 49baaffc7..932dd8add 100644
--- a/Host/Host.csproj.user
+++ b/Host/Host.csproj.user
@@ -3,7 +3,7 @@
C:\Projects\Bewo\BeWo - Main\Host\Properties\PublishProfiles\FolderProfile.pubxml
true
- Release|Any CPU
+ Debug|Any CPU
false
diff --git a/Host/ReportView.aspx.cs b/Host/ReportView.aspx.cs
index 54b4cc743..d0a8a1a84 100644
--- a/Host/ReportView.aspx.cs
+++ b/Host/ReportView.aspx.cs
@@ -24,6 +24,8 @@ using BeWo.Data.Entities;
using BeWo.Service.DCEntityMapper;
using BS.Shared.ReportRequests;
+using SecurityUtils = BeWo.Service.Security.SecurityUtils;
+
namespace Host
{
public partial class ReportView : Page
diff --git a/Model/Changes_2025_06_03 StoredFile.txt b/Model/Changes_2025_06_03 StoredFile.txt
new file mode 100644
index 000000000..47ea60a60
--- /dev/null
+++ b/Model/Changes_2025_06_03 StoredFile.txt
@@ -0,0 +1,19 @@
+CREATE TABLE `StoredFile` (
+`Oid` bigint NOT NULL AUTO_INCREMENT,
+`InsTs` datetime DEFAULT NULL,
+`InsUser` varchar(255) DEFAULT NULL,
+`Notice` varchar(1024) DEFAULT NULL,
+`Tid` int DEFAULT NULL,
+`UdpUser` varchar(255) DEFAULT NULL,
+`Version` bigint DEFAULT NULL,
+`IsActive` tinyint DEFAULT NULL,
+`SystemEntryID` int DEFAULT NULL,
+`FileName` varchar(255),
+`FilePath` varchar(1024),
+`ContentType` varchar(127),
+`Size` bigint,
+`Checksum` varchar(64),
+`BeWoObjectTid` int,
+`BeWoObjectOid` bigint,
+PRIMARY KEY (`Oid`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
\ No newline at end of file
diff --git a/Service/DCEntityMapper/AddressDC_Address.cs b/Service/DCEntityMapper/AddressDC_Address.cs
index 2b228079f..0cac25f42 100644
--- a/Service/DCEntityMapper/AddressDC_Address.cs
+++ b/Service/DCEntityMapper/AddressDC_Address.cs
@@ -4,10 +4,12 @@ using BS.Shared.DataContracts;
namespace BeWo.Service.DCEntityMapper
{
- public class AddressDC_Address : AbstractIDCEntityMapper
+ public class AddressDC_Address : BeWoDataContract_BeWoEntityBase
{
public override AddressDC MergeWithDC(Address pEntity, AddressDC pDataContract)
{
+ base.MergeWithDC(pEntity, pDataContract);
+
pDataContract.AddressLine1 = pEntity.AddressLine1;
pDataContract.AddressLine2 = pEntity.AddressLine2;
pDataContract.Country = pEntity.Country;
@@ -24,6 +26,8 @@ namespace BeWo.Service.DCEntityMapper
public override Address MergeWithEntity(AddressDC pDataContract, Address pEntity)
{
+ base.MergeWithEntity(pDataContract, pEntity);
+
pEntity.AddressLine1 = pDataContract.AddressLine1;
pEntity.AddressLine2 = pDataContract.AddressLine2;
pEntity.Country = pDataContract.Country;
@@ -37,12 +41,5 @@ namespace BeWo.Service.DCEntityMapper
return pEntity;
}
-
- protected override bool AreDCAndEntityEqual(AddressDC pDC, Address pEntity)
- {
- if (pDC.Oid == null)
- return false;
- return pDC.Oid == pEntity.Oid;
- }
}
}
diff --git a/Service/DCEntityMapper/BeWoDataContract_BeWoEntityBase.cs b/Service/DCEntityMapper/BeWoDataContract_BeWoEntityBase.cs
new file mode 100644
index 000000000..c75e188a0
--- /dev/null
+++ b/Service/DCEntityMapper/BeWoDataContract_BeWoEntityBase.cs
@@ -0,0 +1,44 @@
+using BeWo.Data.Access;
+using BeWo.Data.Entities;
+using BS.Shared.DataContracts;
+using BS.Shared.DataContracts.Feature.AI;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BeWo.Service.DCEntityMapper
+{
+ public class BeWoDataContract_BeWoEntityBase : AbstractIDCEntityMapper
+ where Entity : BeWoEntityBase, new()
+ where DataContract : BeWoDataContract, new()
+ {
+ public override DataContract MergeWithDC(Entity pEntity, DataContract pDataContract)
+ {
+ pDataContract.Oid = pEntity.Oid;
+ pDataContract.Version = pEntity.Version;
+ pDataContract.Notice = pEntity.Notice;
+
+ return pDataContract;
+ }
+
+ public override Entity MergeWithEntity(DataContract pDataContract, Entity pEntity)
+ {
+ ConcurrencyCheck(pDataContract.Version, pEntity);
+
+ pEntity.Oid = pDataContract.Oid;
+ pEntity.Version = pDataContract.Version;
+ pEntity.Notice = pDataContract.Notice;
+
+ return pEntity;
+ }
+
+ protected override bool AreDCAndEntityEqual(DataContract pDC, Entity pEntity)
+ {
+ if (pDC.Oid == null)
+ return false;
+ return pDC.Oid == pEntity.Oid;
+ }
+ }
+}
diff --git a/Service/DCEntityMapper/StoredFileDC_StoredFile.cs b/Service/DCEntityMapper/StoredFileDC_StoredFile.cs
new file mode 100644
index 000000000..563244828
--- /dev/null
+++ b/Service/DCEntityMapper/StoredFileDC_StoredFile.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using System.Linq;
+
+using BeWo.Data.Access;
+using BeWo.Data.Entities;
+
+using BS.Shared;
+using BS.Shared.Core;
+using BS.Shared.DataContracts;
+
+namespace BeWo.Service.DCEntityMapper
+{
+ public class StoredFileDC_StoredFile : BeWoDataContract_BeWoEntityBase
+ {
+ public override StoredFileDC MergeWithDC(StoredFile pEntity, StoredFileDC pDataContract)
+ {
+ base.MergeWithDC(pEntity, pDataContract);
+
+ pDataContract.FileName = pEntity.FileName;
+ pDataContract.FilePath = pEntity.FilePath;
+ pDataContract.ContentType = pEntity.ContentType;
+ pDataContract.Size = pEntity.Size;
+ pDataContract.Checksum = pEntity.Checksum;
+ pDataContract.BeWoObjectTid = pEntity.BeWoObjectTid;
+ pDataContract.BeWoObjectOid = pEntity.BeWoObjectOid;
+
+ return pDataContract;
+ }
+
+ public override StoredFile MergeWithEntity(StoredFileDC pDataContract, StoredFile pEntity)
+ {
+ base.MergeWithDC(pEntity, pDataContract);
+
+ pEntity.FileName = pDataContract.FileName;
+ pEntity.FilePath = pDataContract.FilePath;
+ pEntity.ContentType = pDataContract.ContentType;
+ pEntity.Size = pDataContract.Size;
+ pEntity.Checksum = pDataContract.Checksum;
+ pEntity.BeWoObjectTid = pDataContract.BeWoObjectTid;
+ pEntity.BeWoObjectOid = pDataContract.BeWoObjectOid;
+
+ return pEntity;
+ }
+ }
+}
diff --git a/Service/Plugins/ServiceRecordValidator.cs b/Service/Plugins/ServiceRecordValidator.cs
index 3a66c7c45..64d39c892 100644
--- a/Service/Plugins/ServiceRecordValidator.cs
+++ b/Service/Plugins/ServiceRecordValidator.cs
@@ -15,6 +15,8 @@ using BeWo.Service.Configuration;
using BeWo.Data.Security;
using BeWo.Service.Security;
+using SecurityUtils = BeWo.Service.Security.SecurityUtils;
+
namespace BeWo.Service.Plugins
{
public class ServiceRecordValidator : AbstractIDSpecificDefaultClass
diff --git a/Service/Service.csproj b/Service/Service.csproj
index de9d39ef6..dfcdd6cb0 100644
--- a/Service/Service.csproj
+++ b/Service/Service.csproj
@@ -244,6 +244,7 @@
+
@@ -345,6 +346,7 @@
+
diff --git a/Service/ServiceImplementations/DownloadServiceImp.cs b/Service/ServiceImplementations/DownloadServiceImp.cs
index e73bb5a84..71822143c 100644
--- a/Service/ServiceImplementations/DownloadServiceImp.cs
+++ b/Service/ServiceImplementations/DownloadServiceImp.cs
@@ -24,6 +24,8 @@ using BS.Shared.Translation;
using BeWo.Service.Reporting;
using BS.Shared.Core;
+using SecurityUtils = BeWo.Service.Security.SecurityUtils;
+
namespace BeWo.Service.ServiceImplementations
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
diff --git a/Service/ServiceImplementations/OperationsServiceImp.cs b/Service/ServiceImplementations/OperationsServiceImp.cs
index 49993222f..3d08c866e 100644
--- a/Service/ServiceImplementations/OperationsServiceImp.cs
+++ b/Service/ServiceImplementations/OperationsServiceImp.cs
@@ -41,6 +41,8 @@ using Utils = BeWo.Service.Core.Utils;
using System.Collections.Specialized;
using BeWo.ServiceUtils.History;
+using SecurityUtils = BeWo.Service.Security.SecurityUtils;
+
namespace BeWo.Service.ServiceImplementations
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
diff --git a/Shared/BeWoEntityEnums.cs b/Shared/BeWoEntityEnums.cs
index 2ff58ef8b..1a9e8c357 100644
--- a/Shared/BeWoEntityEnums.cs
+++ b/Shared/BeWoEntityEnums.cs
@@ -188,7 +188,8 @@ namespace BS.Shared
AiModel = 179,
AiConversationMessage = 180,
AiContext2BeWoObject = 181,
- AiConfig = 182
+ AiConfig = 182,
+ StoredFile = 183
}
public enum SystemEntryID
diff --git a/Shared/Core/AppError.cs b/Shared/Core/AppError.cs
index b2ae8799b..a15041498 100644
--- a/Shared/Core/AppError.cs
+++ b/Shared/Core/AppError.cs
@@ -33,6 +33,8 @@ namespace BS.Shared.Core
//public static readonly AppError Example = new AppError("Code", "Message");
+ public static readonly AppError LocalFileStorageFileNameInvalidChar = new AppError("DATA.LFS.60001", "Fehler beim Speichern");
+ public static readonly AppError LocalFileStorageFileNameNotEqFilePath = new AppError("DATA.LFS.60002", "Fehler beim Speichern");
public static readonly Func GkvDatenannahmestelleAdresseNotFound = (dc) => new AppError("GKV.70001", $"Unbekannte Datenannahmestelle. Bitte neu in der Organisation {dc.Name} ermitteln");
}
}
diff --git a/Shared/Core/SecurityUtils.cs b/Shared/Core/SecurityUtils.cs
new file mode 100644
index 000000000..ccc3ede27
--- /dev/null
+++ b/Shared/Core/SecurityUtils.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BS.Shared.Core
+{
+ public static class SecurityUtils
+ {
+ private static readonly char[] InvalidFilenameChars = Path.GetInvalidFileNameChars();
+
+ public static bool ContainsInvalidFilenameChars(string fileName)
+ {
+ return fileName.IndexOfAny(InvalidFilenameChars) >= 0;
+ }
+
+ public static string GetChecksum(string filePath)
+ {
+ using (FileStream stream = File.OpenRead(filePath))
+ {
+ var sha = new SHA256Managed();
+ byte[] checksum = sha.ComputeHash(stream);
+ return BitConverter.ToString(checksum).Replace("-", String.Empty);
+ }
+ }
+
+ public static string GetChecksumBuffered(Stream stream)
+ {
+ using (var bufferedStream = new BufferedStream(stream, 1024 * 32))
+ {
+ var sha = new SHA256Managed();
+ byte[] checksum = sha.ComputeHash(bufferedStream);
+ return BitConverter.ToString(checksum).Replace("-", String.Empty);
+ }
+ }
+ }
+}
diff --git a/Shared/DataContracts/InvoiceBaseDC.cs b/Shared/DataContracts/InvoiceBaseDC.cs
index b78e91a24..5f1aa8d6b 100644
--- a/Shared/DataContracts/InvoiceBaseDC.cs
+++ b/Shared/DataContracts/InvoiceBaseDC.cs
@@ -126,6 +126,8 @@ namespace BS.Shared.DataContracts
public IList IInvoiceItems => throw new NotImplementedException();
+ public long? Oid => InvoiceBaseOid;
+
public bool ContainsRecipientAddressData()
{
return !Utils.AreAllNullOrEmpty(this.RecipientStreet, this.RecipientPostCode, this.RecipientTown);
diff --git a/Shared/DataContracts/StoredFileDC.cs b/Shared/DataContracts/StoredFileDC.cs
new file mode 100644
index 000000000..857bad56b
--- /dev/null
+++ b/Shared/DataContracts/StoredFileDC.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace BS.Shared.DataContracts
+{
+ [DataContract]
+ public class StoredFileDC : BeWoDataContract
+ {
+ [DataMember] public string FileName { get; set; }
+ [DataMember] public string FilePath { get; set; }
+ [DataMember] public string ContentType { get; set; }
+ [DataMember] public long Size { get; set; }
+ [DataMember] public string Checksum { get; set; }
+ [DataMember] public int? BeWoObjectTid { get; set; }
+ [DataMember] public long? BeWoObjectOid { get; set; }
+ }
+}
diff --git a/Shared/Interface/IFileStorageDAO.cs b/Shared/Interface/IFileStorageDAO.cs
index 8d2393a50..089ffb5e2 100644
--- a/Shared/Interface/IFileStorageDAO.cs
+++ b/Shared/Interface/IFileStorageDAO.cs
@@ -8,11 +8,11 @@ using System.Threading.Tasks;
namespace BS.Shared.Interface
{
- public interface IFileStorageDAO
- {
- Task SaveFileAsync(string tenant, BWPFeature feature, string fileName, Stream content, CancellationToken cancellationToken = default);
- Task GetFileAsync(string tenant, BWPFeature feature, string fileName, CancellationToken cancellationToken = default);
- Task DeleteFileAsync(string tenant, BWPFeature feature, string fileName, CancellationToken cancellationToken = default);
- Task FileExistsAsync(string tenant, BWPFeature feature, string fileName, CancellationToken cancellationToken = default);
- }
+ //public interface IFileStorageDAO
+ //{
+ // Task SaveFileAsync(BWPFeature feature, string fileName, Stream content, CancellationToken cancellationToken = default);
+ // Task GetFileAsync(BWPFeature feature, string fileName, CancellationToken cancellationToken = default);
+ // Task DeleteFileAsync(BWPFeature feature, string fileName, CancellationToken cancellationToken = default);
+ // Task FileExistsAsync(BWPFeature feature, string fileName, CancellationToken cancellationToken = default);
+ //}
}
diff --git a/Shared/Interface/IInvoiceBase.cs b/Shared/Interface/IInvoiceBase.cs
index 251f24e39..9974a86bf 100644
--- a/Shared/Interface/IInvoiceBase.cs
+++ b/Shared/Interface/IInvoiceBase.cs
@@ -8,6 +8,7 @@ namespace BS.Shared.Interface
{
public interface IInvoiceBase
{
+ long? Oid { get; }
string SenderStreet { get; }
string SenderTown { get; }
string SenderPostCode { get; }
diff --git a/Shared/Interface/IStoredFile.cs b/Shared/Interface/IStoredFile.cs
new file mode 100644
index 000000000..508a58ca0
--- /dev/null
+++ b/Shared/Interface/IStoredFile.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BS.Shared.Interface
+{
+ public interface IStoredFile
+ {
+ string FileName { get; }
+ string FilePath { get; }
+ string ContentType { get; }
+ long Size { get; }
+ string Checksum { get; }
+ int? BeWoObjectTid { get; }
+ long? BeWoObjectOid { get; }
+ }
+}
diff --git a/Shared/Shared.csproj b/Shared/Shared.csproj
index 79056c856..371e4ff4c 100644
--- a/Shared/Shared.csproj
+++ b/Shared/Shared.csproj
@@ -147,6 +147,7 @@
+
@@ -328,6 +329,7 @@
+
@@ -408,6 +410,7 @@
+