diff --git a/global.json b/global.json
new file mode 100644
index 0000000..3b1d787
--- /dev/null
+++ b/global.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "8.0.0",
+ "rollForward": "latestFeature"
+ }
+}
\ No newline at end of file
diff --git a/src/Backend/DiunaBI.Core/DiunaBI.Core.csproj b/src/Backend/DiunaBI.Core/DiunaBI.Core.csproj
index cbf3eab..1920750 100644
--- a/src/Backend/DiunaBI.Core/DiunaBI.Core.csproj
+++ b/src/Backend/DiunaBI.Core/DiunaBI.Core.csproj
@@ -10,5 +10,6 @@
+
\ No newline at end of file
diff --git a/src/Backend/DiunaBI.Core/Interfaces/IDataExporter.cs b/src/Backend/DiunaBI.Core/Interfaces/IDataExporter.cs
new file mode 100644
index 0000000..869a2b5
--- /dev/null
+++ b/src/Backend/DiunaBI.Core/Interfaces/IDataExporter.cs
@@ -0,0 +1,10 @@
+using DiunaBI.Core.Models;
+
+namespace DiunaBI.Core.Interfaces;
+
+public interface IDataExporter
+{
+ string ExporterType { get; }
+ bool CanExport(string exporterType);
+ void Export(Layer layer);
+}
\ No newline at end of file
diff --git a/src/Backend/DiunaBI.Core/Interfaces/IDataImporter.cs b/src/Backend/DiunaBI.Core/Interfaces/IDataImporter.cs
new file mode 100644
index 0000000..4c77890
--- /dev/null
+++ b/src/Backend/DiunaBI.Core/Interfaces/IDataImporter.cs
@@ -0,0 +1,11 @@
+using DiunaBI.Core.Models;
+
+namespace DiunaBI.Core.Interfaces;
+
+public interface IDataImporter
+{
+ string ImporterType { get; }
+
+ bool CanImport(string importerType);
+ void Import(Layer importWorker);
+}
\ No newline at end of file
diff --git a/src/Backend/DiunaBI.Core/Interfaces/IDataProcessor.cs b/src/Backend/DiunaBI.Core/Interfaces/IDataProcessor.cs
new file mode 100644
index 0000000..d48cd85
--- /dev/null
+++ b/src/Backend/DiunaBI.Core/Interfaces/IDataProcessor.cs
@@ -0,0 +1,11 @@
+using DiunaBI.Core.Models;
+
+namespace DiunaBI.Core.Interfaces;
+
+public interface IDataProcessor
+{
+ string ProcessorType { get; }
+
+ bool CanProcess(string processorType);
+ void Process(Layer processWorker);
+}
\ No newline at end of file
diff --git a/src/Backend/DiunaBI.Core/Interfaces/IPlugin.cs b/src/Backend/DiunaBI.Core/Interfaces/IPlugin.cs
new file mode 100644
index 0000000..a4f2ed4
--- /dev/null
+++ b/src/Backend/DiunaBI.Core/Interfaces/IPlugin.cs
@@ -0,0 +1,12 @@
+namespace DiunaBI.Core.Interfaces;
+
+public interface IPlugin
+{
+ string Name { get; }
+ string Version { get; }
+ string Author { get; }
+ string Description { get; }
+
+ void Initialize();
+ void Dispose();
+}
\ No newline at end of file
diff --git a/src/Backend/DiunaBI.Core/Services/PluginManager.cs b/src/Backend/DiunaBI.Core/Services/PluginManager.cs
new file mode 100644
index 0000000..a9119a6
--- /dev/null
+++ b/src/Backend/DiunaBI.Core/Services/PluginManager.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using DiunaBI.Core.Interfaces;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+namespace DiunaBI.Core.Services;
+
+public class PluginManager
+{
+ private readonly ILogger _logger;
+ private readonly IServiceProvider _serviceProvider;
+ private readonly List _processorTypes = new();
+ private readonly List _importerTypes = new();
+ private readonly List _exporters = new();
+ private readonly List _plugins = new();
+
+ public PluginManager(ILogger logger, IServiceProvider serviceProvider)
+ {
+ _logger = logger;
+ _serviceProvider = serviceProvider;
+ }
+
+ public void LoadPluginsFromDirectory(string pluginsPath)
+ {
+ if (!Directory.Exists(pluginsPath))
+ {
+ _logger.LogWarning("Plugins directory not found: {Path}", pluginsPath);
+ return;
+ }
+
+ var dllFiles = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories);
+
+ foreach (var dllFile in dllFiles)
+ {
+ try
+ {
+ LoadPluginFromAssembly(dllFile);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to load plugin from {File}", dllFile);
+ }
+ }
+
+ _logger.LogInformation("Loaded {ProcessorCount} processors and {ImporterCount} importers from {PluginCount} plugins",
+ _processorTypes.Count, _importerTypes.Count, _plugins.Count);
+ }
+
+ private void LoadPluginFromAssembly(string assemblyPath)
+ {
+ _logger.LogDebug("Loading assembly from: {Path}", assemblyPath); // Information -> Debug
+
+ try
+ {
+ var assembly = Assembly.LoadFrom(assemblyPath);
+ _logger.LogDebug("Assembly loaded successfully: {Name}", assembly.FullName); // Information -> Debug
+
+ foreach (var type in assembly.GetTypes())
+ {
+ if (typeof(IDataProcessor).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
+ {
+ _processorTypes.Add(type);
+ _logger.LogDebug("Registered processor: {Type}", type.Name); // Information -> Debug
+ }
+
+ if (typeof(IDataImporter).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
+ {
+ _importerTypes.Add(type);
+ _logger.LogDebug("Registered importer: {Type}", type.Name); // Information -> Debug
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to load assembly from {Path}", assemblyPath); // ZOSTAW jako Error
+ }
+ }
+
+ public IDataProcessor? GetProcessor(string processorType)
+ {
+ foreach (var type in _processorTypes)
+ {
+ try
+ {
+ using var scope = _serviceProvider.CreateScope();
+ var instance = (IDataProcessor)ActivatorUtilities.CreateInstance(scope.ServiceProvider, type);
+
+ if (instance.CanProcess(processorType))
+ {
+ var scopedProvider = _serviceProvider.CreateScope().ServiceProvider;
+ return (IDataProcessor)ActivatorUtilities.CreateInstance(scopedProvider, type);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to create processor instance of type {Type}", type.Name);
+ }
+ }
+ return null;
+ }
+
+ public IDataImporter? GetImporter(string importerType)
+ {
+ foreach (var type in _importerTypes)
+ {
+ try
+ {
+ using var scope = _serviceProvider.CreateScope();
+ var instance = (IDataImporter)ActivatorUtilities.CreateInstance(scope.ServiceProvider, type);
+
+ if (instance.CanImport(importerType))
+ {
+ var scopedProvider = _serviceProvider.CreateScope().ServiceProvider;
+ return (IDataImporter)ActivatorUtilities.CreateInstance(scopedProvider, type);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to create importer instance of type {Type}", type.Name);
+ }
+ }
+ return null;
+ }
+
+ public IDataExporter? GetExporter(string exporterType)
+ {
+ return _exporters.FirstOrDefault(e => e.CanExport(exporterType));
+ }
+
+ public IEnumerable GetAllExporters() => _exporters.AsReadOnly();
+ public IEnumerable GetAllPlugins() => _plugins.AsReadOnly();
+}
\ No newline at end of file
diff --git a/src/Backend/DiunaBI.Plugins.Morska/Exporters/MorskaBaseExporter.cs b/src/Backend/DiunaBI.Plugins.Morska/Exporters/MorskaBaseExporter.cs
new file mode 100644
index 0000000..841be69
--- /dev/null
+++ b/src/Backend/DiunaBI.Plugins.Morska/Exporters/MorskaBaseExporter.cs
@@ -0,0 +1,11 @@
+using DiunaBI.Core.Interfaces;
+using DiunaBI.Core.Models;
+
+namespace DiunaBI.Plugins.Morska.Exporters;
+
+public abstract class MorskaBaseExporter : IDataExporter
+{
+ public abstract string ExporterType { get; }
+ public virtual bool CanExport(string exporterType) => ExporterType == exporterType;
+ public abstract void Export(Layer layer);
+}
\ No newline at end of file
diff --git a/src/Backend/DiunaBI.Plugins.Morska/Exporters/googleSheet.export.cs b/src/Backend/DiunaBI.Plugins.Morska/Exporters/googleSheet.export.cs
index c0cd123..ceaf99d 100644
--- a/src/Backend/DiunaBI.Plugins.Morska/Exporters/googleSheet.export.cs
+++ b/src/Backend/DiunaBI.Plugins.Morska/Exporters/googleSheet.export.cs
@@ -3,11 +3,13 @@ using Google.Apis.Sheets.v4;
using Google.Apis.Sheets.v4.Data;
using DiunaBI.Core.Models;
using Microsoft.Extensions.Configuration;
+using DiunaBI.Plugins.Morska.Exporters;
namespace DiunaBI.Core.Services.Exports;
-public class GoogleSheetExport
+public class GoogleSheetExport : MorskaBaseExporter
{
+ public override string ExporterType => "GoogleSheet";
private readonly GoogleDriveHelper _googleDriveHelper;
private readonly SpreadsheetsResource.ValuesResource _googleSheetValues;
private readonly IConfiguration _configuration;
@@ -20,7 +22,7 @@ public class GoogleSheetExport
_googleSheetValues = googleSheetValues;
_configuration = configuration;
}
- public void Export(Layer layer)
+ public override void Export(Layer layer)
{
if (_googleDriveHelper.Service is null)
{
@@ -29,31 +31,31 @@ public class GoogleSheetExport
try
{
- var data = new List> { new List