diff --git a/SzCli/Program.cs b/SzCli/Program.cs index 56a6eab..c4ebb9a 100644 --- a/SzCli/Program.cs +++ b/SzCli/Program.cs @@ -14,12 +14,245 @@ public class Program { SZ.Init(_fileManager, _logger); - Test.CreateTestData(); + bool shouldClose = false; - var dataset = SZ.SzDataHandler.LoadDataset("test-dataset"); - var dataTemplate = SZ.SzDataHandler.LoadTemplate("szcore-item-basic"); + while (!shouldClose) + { + Console.WriteLine(" -- SZ CLI MAIN MENU -- "); + Console.WriteLine("0: Exit"); + Console.WriteLine("1: Create Template"); + Console.WriteLine("2: Create Dataset"); + Console.WriteLine("3: Evaluate Dataset"); + Console.WriteLine("4: Delete Template"); + Console.WriteLine("5: Delete Dataset"); + // Console.WriteLine("6: Fetch Template"); + // Console.WriteLine("7: Fetch Dataset"); + + Console.Write("> "); + var userInput = Console.ReadLine(); + if (!int.TryParse(userInput, out var result)) + { + Console.WriteLine($"Input was not a number, please try again.\n\n"); + continue; + } - var evalResult = SZ.SzEvaluator.EvaluateDataObject(dataset.DataObjects["test"], dataTemplate); - _logger.Log($"Evaluation test -- Pass?: {evalResult.Pass} {(evalResult.Errors == "" ? "" : (" - Errors: " + evalResult.Errors))}"); + switch (result) + { + case 0: + shouldClose = true; + break; + case 1: + CreateTemplate(); + break; + case 2: + CreateDataset(); + break; + case 3: + EvaluateDataset(); + break; + case 4: + DeleteTemplate(); + break; + case 5: + DeleteDataset(); + break; + default: + Console.WriteLine("Invalid input, please try again"); + break; + } + } + + Console.WriteLine("\n\n"); + } + + private static void DeleteDataset() + { + Console.Write("Dataset ID: "); + var userInput = Console.ReadLine(); + if (string.IsNullOrEmpty(userInput)) + { + Console.WriteLine("Id was null"); + return; + } + SZ.SzDataHandler.DeleteDataset(userInput); + } + + private static void DeleteTemplate() + { + Console.Write("Template ID: "); + var userInput = Console.ReadLine(); + if (string.IsNullOrEmpty(userInput)) + { + Console.WriteLine("Id was null"); + return; + } + SZ.SzDataHandler.DeleteTemplate(userInput); + } + + private static void EvaluateDataset() + { + Console.Write("Dataset ID: "); + var userInput = Console.ReadLine(); + if (string.IsNullOrEmpty(userInput)) + { + Console.WriteLine("Id was null"); + return; + } + var dataset = SZ.SzDataHandler.LoadDataset(userInput); + if (dataset is null) + { + Console.WriteLine($"Dataset with ID {userInput} could not be loaded"); + return; + } + + var evalResult = SZ.SzEvaluator.EvaluateDataset(dataset); + } + + private static void CreateDataset() + { + Console.Write("Enter a name for the dataset: "); + var nameInput = Console.ReadLine(); + if (string.IsNullOrEmpty(nameInput)) + { + Console.WriteLine("Dataset name can't be blank"); + return; + } + + var id = nameInput.ToLower().Replace(" ", "-").Trim(); + + Console.Write("Enter template ID: "); + var templateIdInput = Console.ReadLine(); + if (string.IsNullOrEmpty(templateIdInput)) + { + Console.WriteLine("Template ID can't be blank"); + return; + } + + var template = SZ.SzDataHandler.LoadTemplate(templateIdInput); + if (template is null) + { + Console.WriteLine($"Could not load template with ID {templateIdInput}"); + return; + } + + + + + } + + private static void CreateTemplate() + { + Console.Write("Enter a name for the template: "); + var nameInput = Console.ReadLine(); + if (string.IsNullOrEmpty(nameInput)) + { + Console.WriteLine("Template name can't be blank"); + return; + } + + var id = nameInput.ToLower().Replace(" ", "-").Trim(); + + Console.Write("Enter a data type for the template: "); + var dataTypeInput = Console.ReadLine(); + if (string.IsNullOrEmpty(dataTypeInput)) + { + Console.WriteLine("Template Data Type can't be blank"); + return; + } + + Console.Write("Enter a description for the template: "); + var descInput = Console.ReadLine(); + + var fields = CreateTemplateFields(); + + var newTemplate = new SzDataObjectTemplate() + { + Name = nameInput, + Id = id, + DataObjectType = dataTypeInput, + Description = descInput ?? "", + }; + + foreach (var f in fields) + { + newTemplate.TemplateFields.Add(f.Id, f); + } + + SZ.SzDataHandler.SaveTemplate(newTemplate); + + } + + private static List CreateTemplateFields() + { + bool done = false; + int i = 0; + List list = []; + while (!done) + { + i++; + Console.Write($"Field {i} ID: "); + var idInput = Console.ReadLine(); + if (string.IsNullOrEmpty(idInput)) + { + Console.WriteLine("Field id can't be blank"); + i--; + continue; + } + + if (list.Any(f => f.Id == idInput)) + { + Console.WriteLine($"Field id '{idInput}' must be unique"); + i--; + continue; + } + + Console.WriteLine($"Field {idInput} type: "); + int enumIter = 0; + foreach (var enumType in Enum.GetValues()) + { + Console.WriteLine($"- {enumType}"); + enumIter++; + } + Console.Write("> "); + var typeInput = Console.ReadLine(); + if (!Enum.TryParse(typeInput, out var typeEnumResult)) + { + Console.WriteLine("Field type input was invalid"); + i--; + continue; + } + + // Console.Write("Is the field a list?: "); + // var isListInput = Console.ReadLine(); + // if (!bool.TryParse(isListInput, out var isListResult)) + // { + // Console.WriteLine("Field isList input was invalid"); + // i--; + // continue; + // } + + Console.Write("Add another field? "); + var contInput = Console.ReadLine(); + switch (contInput) + { + case "n": + case "N": + default: + done = true; + break; + case "y": + case "Y": + break; + } + + var newField = new SzTemplateField(){ + Id = idInput, + FieldType = typeEnumResult + }; + + list.Add(newField); + } + + return list; } } diff --git a/SzCore/Defaults/DefaultDatabaseHandler.cs b/SzCore/Defaults/DefaultDatabaseHandler.cs new file mode 100644 index 0000000..1dfac19 --- /dev/null +++ b/SzCore/Defaults/DefaultDatabaseHandler.cs @@ -0,0 +1,33 @@ +using SzCore.DataObjects; + +namespace SzCore.Defaults; + +public class DefaultDatabaseHandler : ISzDatabaseHandler +{ + public bool InternetAllowed { get; set; } = true; + public Dictionary SzDbUrls { get; set; } = []; + + public SzDataset? TryRetrieveDataset(Guid uuid) + { + SZ.Logger.LogWarning("The default database helper is not implemented yet"); + return null; + } + + public Task TryRetrieveDatasetAsync(Guid uuid) + { + SZ.Logger.LogWarning("The default database helper is not implemented yet"); + return null; + } + + public ISzTemplate? TryRetrieveTemplate(Guid uuid) + { + SZ.Logger.LogWarning("The default database helper is not implemented yet"); + return null; + } + + public Task TryRetrieveTemplateAsync(Guid uuid) + { + SZ.Logger.LogWarning("The default database helper is not implemented yet"); + return null; + } +} \ No newline at end of file diff --git a/SzCore/Defaults/DefaultLocalFileManager.cs b/SzCore/Defaults/DefaultLocalFileManager.cs index e4459be..ffa103b 100644 --- a/SzCore/Defaults/DefaultLocalFileManager.cs +++ b/SzCore/Defaults/DefaultLocalFileManager.cs @@ -43,4 +43,18 @@ public class DefaultLocalFileManager : ISzFileManager return null; } } + + public bool DeleteFile(string path) + { + try + { + File.Delete(path); + return true; + } + catch (Exception e) + { + SZ.Logger.LogError("LocalFileManager: Could not delete file. " + e.Message); + return false; + } + } } \ No newline at end of file diff --git a/SzCore/ISzDatabaseHandler.cs b/SzCore/ISzDatabaseHandler.cs index 235e141..7e52f70 100644 --- a/SzCore/ISzDatabaseHandler.cs +++ b/SzCore/ISzDatabaseHandler.cs @@ -1,6 +1,15 @@ +using SzCore.DataObjects; + namespace SzCore; public interface ISzDatabaseHandler { + public bool InternetAllowed { get; set; } + public Dictionary SzDbUrls { get; set; } + + public Task TryRetrieveDatasetAsync(Guid uuid); + public Task TryRetrieveTemplateAsync(Guid uuid); + public SzDataset? TryRetrieveDataset(Guid uuid); + public ISzTemplate? TryRetrieveTemplate(Guid uuid); } \ No newline at end of file diff --git a/SzCore/ISzFileManager.cs b/SzCore/ISzFileManager.cs index bdba2af..9e631c5 100644 --- a/SzCore/ISzFileManager.cs +++ b/SzCore/ISzFileManager.cs @@ -1,3 +1,4 @@ +using System.Security.Cryptography.X509Certificates; using SzCore.DataObjects; namespace SzCore; @@ -10,4 +11,5 @@ public interface ISzFileManager public bool SaveFile(string path, string fileContent); public string? LoadFile(string path); + public bool DeleteFile(string path); } diff --git a/SzCore/SZ.cs b/SzCore/SZ.cs index 80f268d..4ffae83 100644 --- a/SzCore/SZ.cs +++ b/SzCore/SZ.cs @@ -6,6 +6,7 @@ public static class SZ { private static ISzFileManager? _fileManager; private static ISzLogger? _logger; + private static ISzDatabaseHandler? _dbHandler; public static bool IsInitalized { get; private set; } = false; @@ -33,6 +34,16 @@ public static class SZ } } + public static ISzDatabaseHandler DatabaseHandler + { + get + { + CheckInitialization(); + if (_dbHandler is null) throw new Exception("SZ._dbHandler is null"); + return _dbHandler; + } + } + private static readonly Dictionary _services = []; private static readonly List _protectedServices = []; @@ -42,12 +53,13 @@ public static class SZ /// An ISzFileManager instance. /// An ISzLogger instance. /// /// Throws if SZ has already been initalized - public static void Init(ISzFileManager fileManager, ISzLogger logger) + public static void Init(ISzFileManager fileManager, ISzLogger logger, ISzDatabaseHandler databaseHandler) { if (IsInitalized) throw new Exception("Cannot initalize SZ more than once."); _logger = logger; _fileManager = fileManager; + _dbHandler = databaseHandler; if (_logger is null) { @@ -59,10 +71,16 @@ public static class SZ throw new Exception("SZ.Init failed: LocalFileManager was null"); } + if (_dbHandler is null) + { + throw new Exception("SZ.Init failed: DatabaseHandler was null"); + } + IsInitalized = true; AddService(fileManager, true); AddService(logger, true); + AddService(databaseHandler, true); logger.Log(" -- SZ CORE INITALIZED -- "); } diff --git a/SzCore/SzDataHandler.cs b/SzCore/SzDataHandler.cs index 43977e2..8fc3533 100644 --- a/SzCore/SzDataHandler.cs +++ b/SzCore/SzDataHandler.cs @@ -10,6 +10,14 @@ public class SzDataHandler public SzDataHandler(){} + // The client should periodically call this to free memory, probably + private void ClearCache() + { + _loadedDatasets.Clear(); + _loadedTemplates.Clear(); + } + + #region Datasets public bool SaveDataset(SzDataset dataset) { var datasetPath = Path.Combine(SZ.LocalFileManager.DatasetsPath, dataset.Id, "dataset.json"); @@ -24,6 +32,20 @@ public class SzDataHandler } } + public bool DeleteDataset(string datasetId) + { + try + { + Directory.Delete(Path.Combine(SZ.LocalFileManager.DatasetsPath, datasetId), true); + return true; + } + catch (Exception e) + { + SZ.Logger.LogError($"Could not delete Dataset with id '{datasetId}': {e.Message}"); + return false; + } + } + public SzDataset? LoadDataset(string datasetId) { if (_loadedDatasets.TryGetValue(datasetId, out SzDataset? value)) @@ -51,6 +73,14 @@ public class SzDataHandler return parsedDataset; } + public SzDataset CreateDataset() + { + + } + + #endregion + + #region Templates public bool SaveTemplate(ISzTemplate template) { var templatePath = Path.Combine(SZ.LocalFileManager.TemplatesPath, template.Id, "template.json"); @@ -65,6 +95,20 @@ public class SzDataHandler } } + public bool DeleteTemplate(string templateId) + { + try + { + Directory.Delete(Path.Combine(SZ.LocalFileManager.TemplatesPath, templateId), true); + return true; + } + catch (Exception e) + { + SZ.Logger.LogError($"Could not delete Template with id '{templateId}': {e.Message}"); + return false; + } + } + public T? LoadTemplate(string templateId) where T : ISzTemplate { if (_loadedTemplates.TryGetValue(templateId, out ISzTemplate? existing)) @@ -93,13 +137,49 @@ public class SzDataHandler return parsedTemplate; } - // The client should periodically call this to free memory, probably - private void ClearCache() + public SzDataObjectTemplate? CreateDataObjectTemplate(string name, string dataObjectType, string? id = null, string? description = null, List? fields = null) { - _loadedDatasets.Clear(); - _loadedTemplates.Clear(); - } + if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(dataObjectType)) return null; + string newId; + if (!string.IsNullOrEmpty(id)) + { + newId = id; + } + else + { + newId = name.ToLower().Replace(" ", "-").Trim(); + } + + var newTemplate = new SzDataObjectTemplate() + { + Name = name, + Id = newId, + DataObjectType = dataObjectType, + Uuid = Guid.NewGuid(), + Description = description ?? "" + }; + + if (fields is not null) + { + foreach (var field in fields) + { + newTemplate.TemplateFields.Add(field.Id, field); + } + } + + return newTemplate; + + } + #endregion + + #region Other + + public Sz + + #endregion + + #region Tests // Only use these two methods for test purposes, we probably don't want to load all datasets and templates to memory in production private void LoadAllDatasets() { @@ -154,4 +234,5 @@ public class SzDataHandler _loadedTemplates.Add(parsedTemplate.Id, parsedTemplate); } } + #endregion } \ No newline at end of file diff --git a/SzCore/SzEvaluator.cs b/SzCore/SzEvaluator.cs index e8a5c7d..290f878 100644 --- a/SzCore/SzEvaluator.cs +++ b/SzCore/SzEvaluator.cs @@ -6,9 +6,29 @@ namespace SzCore; public class SzEvaluator { - public SzEvaluationResult EvaluateDataObject(SzDataObject dataObject, SzDataObjectTemplate template) + + public SzOperationResult EvaluateDataset(SzDataset dataset) { - if (dataObject is null || template is null) return new SzEvaluationResult(false, "dataObject or template is null"); + if (dataset is null) return new SzOperationResult(false, "Dataset cannot be null"); + + var errors = new StringBuilder(); + + var template = SZ.SzDataHandler.LoadTemplate(dataset.DataObjectTemplateId); + if (template is null) return new SzOperationResult(false, $"Template with id {dataset.DataObjectTemplateId} for Dataset ID {dataset.Id} could not be loaded"); + + foreach (var dataObject in dataset.DataObjects.Values) + { + var evalResult = EvaluateDataObject(dataObject, template); + if (!evalResult.Pass) errors.Append(evalResult.Errors); + } + + var errString = errors.ToString(); + return new SzOperationResult(string.IsNullOrEmpty(errString), errString); + } + + public SzOperationResult EvaluateDataObject(SzDataObject dataObject, SzDataObjectTemplate template) + { + if (dataObject is null || template is null) return new SzOperationResult(false, "dataObject or template is null"); var errors = new StringBuilder(); @@ -36,10 +56,10 @@ public class SzEvaluator } var errString = errors.ToString().Trim(); - return new SzEvaluationResult(string.IsNullOrEmpty(errString), string.IsNullOrEmpty(errString) ? "" : errString); + return new SzOperationResult(string.IsNullOrEmpty(errString), string.IsNullOrEmpty(errString) ? "" : errString); } - public SzEvaluationResult DoesFieldMatchTemplateField(SzField field, SzTemplateField templateField) + public SzOperationResult DoesFieldMatchTemplateField(SzField field, SzTemplateField templateField) { var errors = new StringBuilder(); @@ -48,13 +68,13 @@ public class SzEvaluator if (field.IsList != templateField.IsList) errors.AppendLine($"Field '{field.Id}' IsList mismatch: Expected {templateField.IsList}"); var errString = errors.ToString().Trim(); - return new SzEvaluationResult(string.IsNullOrEmpty(errString), errString); + return new SzOperationResult(string.IsNullOrEmpty(errString), errString); } - public SzEvaluationResult EvaluateFieldValue(SzField field) + public SzOperationResult EvaluateFieldValue(SzField field) { if (string.IsNullOrWhiteSpace(field.Value)) - return new SzEvaluationResult(true, ""); + return new SzOperationResult(true, ""); var errors = new StringBuilder(); @@ -91,12 +111,6 @@ public class SzEvaluator } var errString = errors.ToString().Trim(); - return new SzEvaluationResult(string.IsNullOrEmpty(errString), errString); + return new SzOperationResult(string.IsNullOrEmpty(errString), errString); } } - -public class SzEvaluationResult(bool pass, string errors = "None") -{ - public bool Pass = pass; - public string Errors = errors; -} diff --git a/SzCore/SzOperationResult.cs b/SzCore/SzOperationResult.cs new file mode 100644 index 0000000..1ec10a2 --- /dev/null +++ b/SzCore/SzOperationResult.cs @@ -0,0 +1,7 @@ +namespace SzCore; + +public class SzOperationResult(bool pass, string errors = "None") +{ + public bool Pass = pass; + public string Errors = errors; +}