Continuing building

master
Eugene ;) 3 years ago
parent 73a6125faf
commit 20a4a9ebbf

@ -27,4 +27,21 @@ namespace Seenginx.Models
public void SetData(D data) => Data = data;
}
public class Result
{
public bool AllOk { get; private set; } = true;
public string ErrorMessage { get; private set; }
public Exception Exception { get; private set; } = null;
public Result Invalidate(string errorMessage, Exception exception = null)
{
AllOk = false;
ErrorMessage = errorMessage;
if (exception != null)
Exception = exception;
return this;
}
}
}

@ -7,7 +7,7 @@
<div class="control has-icons-left is-expanded">
<input formnovalidate @oninput="e => SearchInputChanged(e.Value.ToString())" @bind-value="SearchInput" class="input is-rounded is-small neoInput" type="text" placeholder="Search...">
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-file-search-outline"></i>
<i class="mdi mdi-file-search"></i>
</span>
</div>
</div>
@ -17,33 +17,39 @@
@if (IsAnyFileSelected)
{
<div class="field is-grouped">
<div class="control is-expanded borderRBig neoInput has-text-centered has-icons-left">
<input class="input is-5 is-rounded is-small neoInput" type="text" placeholder="Search..."
disabled="@(SelectedFile.CanBeDeleted ? null : "disabled")" @bind-value="SelectedFile.Name">
<span class="icon is-small is-left @(ConfigHasChanged ? "has-text-danger" : "has-text-dark")">
<i class="mdi @(ConfigHasChanged ? "mdi-not-equal" : "mdi-equal")"></i>
</span>
<div class="control is-expanded borderRBig neomorphXSmall has-icons-left has-text-centered">
<span>@SelectedFile.Name</span>
</div>
<div class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnFileRenameClick">
<p class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnFileRenameClick" title="Rename configuration">
<span class="icon is-medium">
<i class="mdi mdi-pencil-outline"></i>
<i class="mdi mdi-pencil"></i>
</span>
</button>
</div>
<div class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnFileCloseClick">
</p>
@if (!string.IsNullOrEmpty(SelectedFile.DraftBody))
{
<p class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnLoadDraftClick" title="Load draft">
<span class="icon is-medium">
<i class="mdi mdi-content-save-edit"></i>
</span>
</button>
</p>
}
<p class="control">
<button class="button is-small is-rounded neoBtnSmall" @onclick="OnFileCloseClick" title="Close">
<span class="icon is-medium">
<i class="mdi mdi-close"></i>
</span>
</button>
</div>
</p>
</div>
}
else
{
<div class="field">
<div class="control is-expanded borderRBig neoInput has-text-centered"><span>···</span></div>
<div class="control is-expanded borderRBig neomorphXSmall has-text-centered"><span>···</span></div>
</div>
}
</div>
@ -52,8 +58,8 @@
<div class="filesList">
@foreach (var file in Files)
{
<div @onclick="async e => await OnFileClick(e,file)" title="@(string.IsNullOrEmpty(file.Folder) ? $"/{file.Name}" : $"/{file.Folder}/{file.Name}")" @key="file" class="confFile borderRSmall isFinger neoFile @file.IsVisible @file.IsSelected">
<p class="has-text-weight-bold ellipsis"><span class="icon @(file.CanBeDeleted ? null : "has-text-danger")"><i class="mdi mdi-file-cog-outline"></i></span> @file.Name</p>
<div @onclick="async e => await OnFileClick(e,file)" title="@file.FullPath" @key="file" class="confFile borderRSmall isFinger neoFile @file.IsVisible @file.IsSelected">
<p class="has-text-weight-bold ellipsis"><span class="icon @(file.CanBeDeleted ? null : "has-text-danger")"><i class="mdi mdi-file-cog"></i></span> @file.Name</p>
</div>
}
</div>
@ -91,10 +97,10 @@
<button @onclick="OnUndoChanges" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-dark"><i class="mdi mdi-undo-variant"></i></span> <span>Undo changes</span></button>
@if (HasTesting)
{
<button @onclick="OnTest" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-danger"><i class="mdi mdi-alert-outline"></i></span> <span>Test</span></button>
<button @onclick="OnTest" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-danger"><i class="mdi mdi-alert"></i></span> <span>Test</span></button>
}
<button @onclick="OnSaveDraft" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-light"><i class="mdi mdi-content-save-outline"></i></span> <span>@(string.IsNullOrEmpty(SelectedFile.DraftBody) ? "Create" : "Save") draft</span></button>
<button @onclick="OnSave" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-success"><i class="mdi mdi-content-save-all-outline"></i></span> <span>Save</span></button>
<button @onclick="OnSaveDraft" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-light"><i class="mdi mdi-content-save"></i></span> <span>@(string.IsNullOrEmpty(SelectedFile.DraftBody) ? "Create" : "Save") draft</span></button>
<button @onclick="OnSave" class="button is-rounded neoBtnSmall is-small has-icon-left noBottomMargin"><span class="icon is-left has-text-success"><i class="mdi mdi-content-save-all"></i></span> <span>Save</span></button>
</div>
}
else

@ -33,7 +33,6 @@ namespace Seenginx.Components
[Parameter] public CFile SelectedFile { get; set; } = default;
protected string SearchInput { get; set; }
private bool ConfigHasChanged => (string.IsNullOrEmpty(SelectedFile.DraftBody) ? false : SelectedFile.Body != SelectedFile.DraftBody);
protected bool IsAnyFileSelected => SelectedFile != default;
protected string IsSelectedFileDeletable
@ -90,6 +89,11 @@ namespace Seenginx.Components
await RenameFileCallback.InvokeAsync(null);
}
protected async Task OnLoadDraftClick(MouseEventArgs e)
{
await JsRuntime.InvokeVoidAsync("UpdateEditor", SelectedFile.DraftBody);
}
protected async Task OnFileCloseClick(MouseEventArgs e)
{
Files.ForEach(f => f.Deselect());

@ -1,7 +1,8 @@
@inherits NginxBase
@page "/nginx"
<FilesWithEditor CFile="ConfigFile" Files="ConfigFiles" SelectedFile="SelectedFile" SelectedFileChanged="SelectedFileChanged"
TestConfiguration="TestConfiguration" DeleteFileCallback="DeleteFile" ShowAddFileModal="ShowAddFileModal"
TestConfiguration="TestConfiguration" DeleteFileCallback="DeleteFile" ShowAddFileModal="AddFileModal"
RenameFileCallback="RenameFileModal"
HasTesting="true" SaveFileCallback="SaveFileAsync" SaveDraftFileCallback="SaveDraftFileAsync">
</FilesWithEditor>

@ -17,7 +17,6 @@ namespace Seenginx.Pages
public class NginxBase : ComponentBase
{
[Inject] public INginxService NginxService { get; set; }
[Inject] public IFileManager FileService { get; set; }
[Inject] public IModalService Modal { get; set; }
public string InputSearch { get; set; }
@ -47,7 +46,7 @@ namespace Seenginx.Pages
SelectedFile = configFile;
}
public async Task ShowAddFileModal()
public async Task AddFileModal()
{
var parameters = new ModalParameters();
parameters.Add(nameof(Templates), Templates);
@ -57,7 +56,7 @@ namespace Seenginx.Pages
if (result.Cancelled) return;
var validationResult = await NginxService.ValidateNewConfigurationAsync((NewFileForm)result.Data);
var validationResult = await NginxService.ValidateForAddFileAsync((NewFileForm)result.Data);
if (!validationResult.AllOk)
{
@ -77,14 +76,70 @@ namespace Seenginx.Pages
SelectedFile.Select();
}
public async Task RenameFileModal()
{
var parameters = new ModalParameters();
parameters.Add(nameof(RenameForm.Name), SelectedFile.Name);
var resultAwait = Modal.Show<RenameForm>(string.Empty, parameters);
var result = await resultAwait.Result;
if (result.Cancelled) return;
var validationResult = await NginxService.ValidateForRenameFileAsync(ConfigFiles, SelectedFile, result.Data.ToString());
if (!validationResult.AllOk)
{
var popupAwait = Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, validationResult.ErrorMessage));
await popupAwait.Result;
return;
}
var renameResult = await NginxService.RenameFileAsync(SelectedFile, $"{result.Data}.conf");
if (!renameResult.AllOk)
{
var popupAwait = Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, renameResult.ErrorMessage));
await popupAwait.Result;
return;
}
SelectedFile.Name = result.Data.ToString();
}
public async Task SaveFileAsync()
{
var saveUpdateResult = await FileService.SaveFileAsync(SelectedFile);
var validationResult = await NginxService.ValidateForSaveFileAsync(SelectedFile);
if (!validationResult.AllOk)
{
await Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, validationResult.ErrorMessage)).Result;
return;
}
var saveResult = await NginxService.SaveFileAsync(SelectedFile);
if (!saveResult.AllOk)
{
await Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, saveResult.ErrorMessage)).Result;
return;
}
}
public async Task SaveDraftFileAsync()
{
var saveUpdateDraftResult = await FileService.SaveDraftFileAsync(SelectedFile);
var validationResult = await NginxService.ValidateForSaveDraftFileAsync(SelectedFile);
if (!validationResult.AllOk)
{
await Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, validationResult.ErrorMessage)).Result;
return;
}
var saveDraftResult = await NginxService.SaveDraftFileAsync(SelectedFile);
if (!saveDraftResult.AllOk)
{
await Modal.Show<GenericPopup>(string.Empty, new ModalParameters().Setup(PopupType.Ok, saveDraftResult.ErrorMessage)).Result;
return;
}
}
public async Task TestConfiguration()

@ -104,6 +104,12 @@
border: none !important;
transform: scale(1.1);
}
&Plain {
box-shadow: -2px -2px 4px rgba($light-shadow, .5), 2px 2px 4px rgba($dark-shadow, .5);
background: none !important;
border: none !important;
}
}
}

@ -1,83 +0,0 @@
using Seenginx.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Seenginx.Services
{
public class FileManager : IFileManager
{
public async Task<Result<ConfigFile>> SaveFileAsync(ConfigFile configFile)
{
var result = new Result<ConfigFile>(configFile);
try
{
var validationResult = ValidForUpdate(configFile);
if (!validationResult.AllOk)
return result.Invalidate($"Failed validation for: {validationResult.ErrorMessage}");
await File.WriteAllTextAsync(configFile.FullPath, configFile.Body);
return result;
}
catch (Exception ex)
{
return result.Invalidate($"Exception at {nameof(SaveFileAsync)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex);
}
}
public async Task<Result<ConfigFile>> SaveDraftFileAsync(ConfigFile configFile)
{
var result = new Result<ConfigFile>(configFile);
try
{
var validationResult = ValidForUpdate(configFile);
if (!validationResult.AllOk)
return result.Invalidate($"Failed validation for: {validationResult.ErrorMessage}");
await File.WriteAllTextAsync($"{configFile.FullPath}.draft", configFile.DraftBody);
return result;
}
catch (Exception ex)
{
return result.Invalidate($"Exception at {nameof(SaveDraftFileAsync)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex);
}
}
public Result<bool> DeleteFile(ConfigFile configFile)
{
var result = new Result<bool>();
try
{
var validationResult = ValidForUpdate(configFile);
if (!validationResult.AllOk)
return result.Invalidate($"Failed validation for: {validationResult.ErrorMessage}");
File.Delete(configFile.FullPath);
if (File.Exists($"{configFile.FullPath}.draft"))
File.Delete($"{configFile.FullPath}.draft");
return result;
}
catch (Exception ex)
{
return result.Invalidate($"Exception at {nameof(DeleteFile)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex);
}
}
private Result<string> ValidForUpdate(ConfigFile configFile)
{
var result = new Result<string>();
if (!Directory.Exists(Directory.GetDirectoryRoot(configFile.FullPath)))
return result.Invalidate($"Directory '{Directory.GetDirectoryRoot(configFile.FullPath)}' doesn't exist.");
if (!File.Exists(configFile.FullPath))
return result.Invalidate($"File '{configFile.FullPath}' doesn't exist.");
return result;
}
}
}

@ -1,15 +0,0 @@
using Seenginx.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Seenginx.Services
{
public interface IFileManager
{
Task<Result<ConfigFile>> SaveFileAsync(ConfigFile configFile);
Task<Result<ConfigFile>> SaveDraftFileAsync(ConfigFile configFile);
Result<bool> DeleteFile(ConfigFile configFile);
}
}

@ -8,12 +8,22 @@ namespace Seenginx.Services
{
Task<IEnumerable<ConfigFile>> GetFilesAsync();
Task<IEnumerable<Template>> GetTemplates();
Task<Result<string>> TestFileAsync(ConfigFile configFile);
Task<Result> ValidateForAddFileAsync(NewFileForm newFileForm);
Task<Result<ConfigFile>> AddFileAsync(NewFileForm newFileForm);
Task<Result> ValidateForSaveFileAsync(ConfigFile configFile);
Task<Result<ConfigFile>> SaveFileAsync(ConfigFile configFile);
Task<Result> ValidateForSaveDraftFileAsync(ConfigFile configFile);
Task<Result<ConfigFile>> SaveDraftFileAsync(ConfigFile configFile);
Task<Result<bool>> RenameFileAsync(ConfigFile configFile);
Task<Result<bool>> DeleteFileAsync(ConfigFile configFile);
Task<Result<bool>> ValidateNewConfigurationAsync(NewFileForm newFileForm);
Task<Result> ValidateForRenameFileAsync(List<ConfigFile> configFiles, ConfigFile configFile, string newName);
Task<Result> RenameFileAsync(ConfigFile configFile, string newName);
Task<Result> ValidateForDeleteFileAsync(ConfigFile configFile);
Task<Result> DeleteFileAsync(ConfigFile configFile);
}
}

@ -20,9 +20,122 @@ namespace Seenginx.Services
ConfigPaths = configPaths;
}
public async Task<Result<bool>> ValidateNewConfigurationAsync(NewFileForm newFileForm)
public async Task<IEnumerable<ConfigFile>> GetFilesAsync()
{
await Task.Run(() => { });
var rootConfigs = Directory.GetFiles(ConfigPaths.NginxPath, "*.conf");
var rootDraftConfigs = Directory.GetFiles(ConfigPaths.NginxPath, "*.conf.draft");
var confdConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "conf.d"), "*.conf");
var confDraftConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "conf.d"), "*.conf.draft");
var sitesAvailableConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "sites-available"), "*.conf");
var sitesAvailableDraftConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "sites-available"), "*.conf.draft");
var rootConfigFiles = rootConfigs.Select(fp =>
{
var name = Path.GetFileNameWithoutExtension(fp);
var configFile = new ConfigFile();
configFile.CanBeDeleted = false;
configFile.Folder = string.Empty;
configFile.LastUpdated = File.GetLastWriteTime(fp);
configFile.Name = name;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, $"{configFile.Name}.conf");
configFile.Body = File.ReadAllText(fp);
if (rootDraftConfigs.Any(cfp => cfp.Contains(name)))
configFile.DraftBody = File.ReadAllText(rootDraftConfigs.First(cfp => cfp.Contains(name)));
return configFile;
});
var confdConfigFiles = confdConfigs.Select(fp =>
{
var fileName = Path.GetFileNameWithoutExtension(fp);
var configFile = new ConfigFile();
configFile.CanBeDeleted = true;
configFile.Folder = "conf.d";
configFile.LastUpdated = File.GetLastWriteTime(fp);
configFile.Name = fileName;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf");
configFile.Body = File.ReadAllText(fp);
if (confDraftConfigs.Any(cfp => cfp.Contains(fileName)))
configFile.DraftBody = File.ReadAllText(confDraftConfigs.First(cfp => cfp.Contains(fileName)));
return configFile;
});
var sitesAvailableConfigFiles = sitesAvailableConfigs.Select(fp =>
{
var fileName = Path.GetFileNameWithoutExtension(fp);
var configFile = new ConfigFile();
configFile.CanBeDeleted = true;
configFile.Folder = "sites-available";
configFile.LastUpdated = File.GetLastWriteTime(fp);
configFile.Name = fileName;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf");
configFile.Body = File.ReadAllText(fp);
if (sitesAvailableDraftConfigs.Any(cfp => cfp.Contains(fileName)))
configFile.DraftBody = File.ReadAllText(sitesAvailableDraftConfigs.First(cfp => cfp.Contains(fileName)));
return configFile;
});
//var sitesEnabledConfigFiles = sitesEnabledConfigs.Select(fp =>
//{
// var fileName = Path.GetFileName(fp);
// var configFile = new ConfigFile();
// configFile.CanBeDeleted = true;
// configFile.Folder = "/sites-enabled";
// configFile.LastUpdated = File.GetLastWriteTime(fp);
// configFile.Name = fileName;
// configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder.Replace("/", string.Empty), configFile.Name);
// configFile.Body = File.ReadAllText(fp);
// configFile.DraftName = fileName;
// configFile.DraftBody = configFile.Body;
// if (confDraftConfigs.Any(cfp => cfp.Contains(fileName)))
// {
// configFile.DraftName = Path.GetFileName(confDraftConfigs.First(cfp => cfp.Contains(fileName)));
// configFile.DraftBody = File.ReadAllText(confDraftConfigs.First(cfp => cfp.Contains(fileName)));
// }
// return configFile;
//});
var finalList = new List<ConfigFile>();
finalList.AddRange(rootConfigFiles);
finalList.AddRange(confdConfigFiles);
finalList.AddRange(sitesAvailableConfigFiles);
//finalList.AddRange(sitesEnabledConfigFiles);
finalList = finalList.OrderBy(cf => cf.Name).ToList();
return finalList;
}
public async Task<IEnumerable<Template>> GetTemplates()
{
var templates = new List<Template>();
try
{
var nginxTemplateDirectory = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "templates", "nginx");
var nginxTemplateFiles = Directory.GetFiles(nginxTemplateDirectory, "*.template");
foreach (var templateFilePath in nginxTemplateFiles)
{
var template = new Template();
var templateFileLines = await File.ReadAllLinesAsync(templateFilePath);
template.Name = templateFileLines.FirstOrDefault();
template.Code = string.Join(Environment.NewLine, templateFileLines.Skip(2));
templates.Add(template);
}
return templates;
}
catch (Exception ex)
{
throw ex;
}
}
public async Task<Result> ValidateForAddFileAsync(NewFileForm newFileForm)
{
var validationResult = new Result<bool>();
var validationResult = new Result();
try
{
var filePath = Path.Combine(ConfigPaths.NginxPath, "conf.d", $"{newFileForm.Name}.conf");
@ -34,7 +147,7 @@ namespace Seenginx.Services
}
catch (Exception ex)
{
return validationResult.Invalidate($"Exception at {nameof(ValidateNewConfigurationAsync)}()", ex);
return validationResult.Invalidate($"Exception at {nameof(ValidateForAddFileAsync)}()", ex);
}
}
@ -45,11 +158,10 @@ namespace Seenginx.Services
{
var newFile = new ConfigFile();
newFile.Name = $"{newFileForm.Name}.conf";
newFile.Folder = "/conf.d";
newFile.FullPath = Path.Combine(ConfigPaths.NginxPath, "conf.d", newFile.Name);
newFile.Folder = "conf.d";
newFile.FullPath = Path.Combine(ConfigPaths.NginxPath, newFile.Folder, newFile.Name);
newFile.Body = newFileForm.SelectedTemplate == 0.ToString() ? string.Empty : (await GetTemplates()).SingleOrDefault(t => t.Name == newFileForm.SelectedTemplate)?.Code;
newFile.LastUpdated = DateTime.UtcNow;
newFile.DraftBody = newFile.Body;
await File.WriteAllTextAsync(newFile.FullPath, newFile.Body, Encoding.UTF8);
@ -63,9 +175,26 @@ namespace Seenginx.Services
}
}
public async Task<Result<bool>> DeleteFileAsync(ConfigFile configFile)
public async Task<Result> ValidateForDeleteFileAsync(ConfigFile configFile)
{
var validationResult = new Result();
try
{
if (File.Exists(configFile.FullPath))
return validationResult.Invalidate($"File '{configFile.FullPath}' not found.");
return validationResult;
}
catch (Exception ex)
{
return validationResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result> DeleteFileAsync(ConfigFile configFile)
{
var result = new Result<bool>(true);
var result = new Result();
try
{
if (!File.Exists(configFile.FullPath))
@ -81,12 +210,21 @@ namespace Seenginx.Services
}
}
public async Task<Result<string>> TestFileAsync(ConfigFile configFile)
public async Task<Result> ValidateForSaveFileAsync(ConfigFile configFile)
{
await Task.Run(() => { });
var result = new Result<string>();
result.SetData("Uhu");
return result;
var validationResult = new Result();
try
{
if (File.Exists(configFile.FullPath))
return validationResult.Invalidate($"File '{configFile.FullPath}' not found.");
return validationResult;
}
catch (Exception ex)
{
return validationResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result<ConfigFile>> SaveFileAsync(ConfigFile configFile)
@ -94,7 +232,7 @@ namespace Seenginx.Services
var saveResult = new Result<ConfigFile>();
try
{
await File.WriteAllTextAsync(Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name), configFile.Body, Encoding.UTF8);
await File.WriteAllTextAsync(Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf"), configFile.Body, Encoding.UTF8);
return saveResult;
}
@ -104,12 +242,31 @@ namespace Seenginx.Services
}
}
public async Task<Result> ValidateForSaveDraftFileAsync(ConfigFile configFile)
{
var validationResult = new Result();
try
{
var draftPathName = $"{configFile.FullPath}.draft";
if (File.Exists(draftPathName))
return validationResult.Invalidate($"File '{draftPathName}' not found.");
return validationResult;
}
catch (Exception ex)
{
return validationResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result<ConfigFile>> SaveDraftFileAsync(ConfigFile configFile)
{
var saveDraftResult = new Result<ConfigFile>();
try
{
await File.WriteAllTextAsync(Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.draft"), configFile.DraftBody, Encoding.UTF8);
await File.WriteAllTextAsync(Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf.draft"), configFile.DraftBody, Encoding.UTF8);
return saveDraftResult;
}
@ -119,129 +276,66 @@ namespace Seenginx.Services
}
}
public async Task<Result<bool>> RenameFileAsync(ConfigFile configFile, string newName)
{
File.Move()
}
public async Task<IEnumerable<ConfigFile>> GetFilesAsync()
public async Task<Result> ValidateForRenameFileAsync(List<ConfigFile> configFiles, ConfigFile selectedConfigFile, string newName)
{
await Task.Run(() => { });
var rootConfigs = Directory.GetFiles(ConfigPaths.NginxPath, "*.conf");
var rootDraftConfigs = Directory.GetFiles(ConfigPaths.NginxPath, "*.conf.draft");
var renameResult = new Result();
try
{
var confdConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "conf.d"), "*.conf");
var confDraftConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "conf.d"), "*.conf.draft");
var sitesAvailableConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "sites-available"), "*.conf");
var sitesAvailableDraftConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "sites-available"), "*.conf.draft");
if(configFiles.Count(cf => cf.Name == newName) > 0)
return renameResult.Invalidate($"File '{selectedConfigFile.FullPath}' already exists.");
var rootConfigFiles = rootConfigs.Select(fp =>
{
var fileName = Path.GetFileName(fp);
var configFile = new ConfigFile();
configFile.CanBeDeleted = false;
configFile.Folder = string.Empty;
configFile.LastUpdated = File.GetLastWriteTime(fp);
configFile.Name = fileName;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Name);
configFile.Body = File.ReadAllText(fp);
if (rootDraftConfigs.Any(cfp => cfp.Contains(fileName)))
configFile.DraftBody = File.ReadAllText(rootDraftConfigs.First(cfp => cfp.Contains(fileName)));
return configFile;
});
var confdConfigFiles = confdConfigs.Select(fp =>
{
var fileName = Path.GetFileName(fp);
var configFile = new ConfigFile();
configFile.CanBeDeleted = true;
configFile.Folder = "conf.d";
configFile.LastUpdated = File.GetLastWriteTime(fp);
configFile.Name = fileName;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name);
configFile.Body = File.ReadAllText(fp);
if (confDraftConfigs.Any(cfp => cfp.Contains(fileName)))
configFile.DraftBody = File.ReadAllText(confDraftConfigs.First(cfp => cfp.Contains(fileName)));
return configFile;
});
var sitesAvailableConfigFiles = sitesAvailableConfigs.Select(fp =>
{
var fileName = Path.GetFileName(fp);
var configFile = new ConfigFile();
configFile.CanBeDeleted = true;
configFile.Folder = "sites-available";
configFile.LastUpdated = File.GetLastWriteTime(fp);
configFile.Name = fileName;
configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name);
configFile.Body = File.ReadAllText(fp);
if (sitesAvailableDraftConfigs.Any(cfp => cfp.Contains(fileName)))
configFile.DraftBody = File.ReadAllText(sitesAvailableDraftConfigs.First(cfp => cfp.Contains(fileName)));
return configFile;
});
//var sitesEnabledConfigFiles = sitesEnabledConfigs.Select(fp =>
//{
// var fileName = Path.GetFileName(fp);
// var configFile = new ConfigFile();
// configFile.CanBeDeleted = true;
// configFile.Folder = "/sites-enabled";
// configFile.LastUpdated = File.GetLastWriteTime(fp);
// configFile.Name = fileName;
// configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder.Replace("/", string.Empty), configFile.Name);
// configFile.Body = File.ReadAllText(fp);
// configFile.DraftName = fileName;
// configFile.DraftBody = configFile.Body;
// if (confDraftConfigs.Any(cfp => cfp.Contains(fileName)))
// {
// configFile.DraftName = Path.GetFileName(confDraftConfigs.First(cfp => cfp.Contains(fileName)));
// configFile.DraftBody = File.ReadAllText(confDraftConfigs.First(cfp => cfp.Contains(fileName)));
// }
// return configFile;
//});
var finalList = new List<ConfigFile>();
finalList.AddRange(rootConfigFiles);
finalList.AddRange(confdConfigFiles);
finalList.AddRange(sitesAvailableConfigFiles);
//finalList.AddRange(sitesEnabledConfigFiles);
if (File.Exists(selectedConfigFile.FullPath))
return renameResult.Invalidate($"Original file '{selectedConfigFile.FullPath}' not found.");
finalList = finalList.OrderBy(cf => cf.Name).ToList();
var newPathName = Path.Combine(ConfigPaths.NginxPath, selectedConfigFile.Folder, $"{newName}.conf");
if (File.Exists(newPathName))
return renameResult.Invalidate($"The file '{newPathName}' already exists.");
return finalList;
return renameResult;
}
catch (Exception ex)
{
return renameResult.Invalidate(ex.Message, ex);
}
}
public async Task<IEnumerable<Template>> GetTemplates()
public async Task<Result> RenameFileAsync(ConfigFile configFile, string newName)
{
var templates = new List<Template>();
var renameResult = new Result();
try
{
var nginxTemplateDirectory = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "templates", "nginx");
var nginxTemplateFiles = Directory.GetFiles(nginxTemplateDirectory, "*.template");
var originalPathName = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, $"{configFile.Name}.conf");
var newPathName = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, newName);
foreach (var templateFilePath in nginxTemplateFiles)
{
var template = new Template();
var templateFileLines = await File.ReadAllLinesAsync(templateFilePath);
template.Name = templateFileLines.FirstOrDefault();
template.Code = string.Join(Environment.NewLine, templateFileLines.Skip(2));
templates.Add(template);
}
File.Move(originalPathName, newPathName, overwrite: false);
return templates;
return renameResult;
}
catch (Exception ex)
{
throw ex;
return renameResult.Invalidate(ex.Message, ex);
}
}
public async Task<Result<string>> TestFileAsync(ConfigFile configFile)
{
await Task.Run(() => { });
var result = new Result<string>();
result.SetData("Uhu");
return result;
}
//public async Task<Result<bool>> DeleteFileAsync(ConfigFile configFile)
//public async Task<Result> DeleteFileAsync(ConfigFile configFile)
//{
// var result = new Result<bool>(true);
// var result = new Result(true);
// try
// {
// return result;

@ -17,7 +17,7 @@
@key="@ActiveNav.Keys.ElementAt(0)"
ActiveClass="@ActiveNav.GetValueOrDefault("nginx")"
@onclick="@(e => SelectMenuItem("nginx"))">
<span class="mdi mdi-file-cog-outline"></span>
<span class="mdi mdi-file-cog"></span>
Configuration
</NavLink>
</li>
@ -26,7 +26,7 @@
@key="@ActiveNav.Keys.ElementAt(1)"
ActiveClass="@ActiveNav.GetValueOrDefault("nginxlogs")"
@onclick="@(e => SelectMenuItem("nginxlogs"))">
<span class="mdi mdi-information-outline"></span>
<span class="mdi mdi-information"></span>
Logs
</NavLink>
</li>
@ -41,7 +41,7 @@
@key="@ActiveNav.Keys.ElementAt(2)"
ActiveClass="@ActiveNav.GetValueOrDefault("systemd")"
@onclick="@(e => SelectMenuItem("systemd"))">
<span class="mdi mdi-file-cog-outline"></span>
<span class="mdi mdi-file-cog"></span>
Configuration
</NavLink>
</li>
@ -50,7 +50,7 @@
@key="@ActiveNav.Keys.ElementAt(3)"
ActiveClass="@ActiveNav.GetValueOrDefault("systemdlogs")"
@onclick="@(e => SelectMenuItem("systemdlogs"))">
<span class="mdi mdi-information-outline"></span>
<span class="mdi mdi-information"></span>
Logs
</NavLink>
</li>
@ -65,7 +65,7 @@
@key="@ActiveNav.Keys.ElementAt(4)"
ActiveClass="@ActiveNav.GetValueOrDefault("dmesg")"
@onclick="@(e => SelectMenuItem("dmesg"))">
<span class="mdi mdi-information-outline"></span>
<span class="mdi mdi-information"></span>
Logs
</NavLink>
</li>

@ -21,7 +21,7 @@
</select>
</div>
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-puzzle-outline"></i>
<i class="mdi mdi-puzzle"></i>
</span>
</div>
<p class="help">Any template to quick setup the configuration</p>
@ -32,7 +32,7 @@
<div class="control has-icons-left">
<input class="input is-rounded is-small neoInput" type="text" placeholder="Name" @bind="TemplateName">
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-file-code-outline"></i>
<i class="mdi mdi-file-code"></i>
</span>
</div>
<p class="help">Name it the same as the service which is going to run behind</p>

@ -0,0 +1,65 @@
<div class="modal-content neomorph">
<div class="modal-card-head">
<h4 class="modal-card-title has-text-centered">
Change the configuration name
</h4>
</div>
<div class="modal-card-body">
<EditForm Model="Name">
<div class="field">
<label class="label">New configuration name</label>
<div class="control has-icons-left">
<input class="input is-rounded is-small neoInput" type="text" placeholder="Name" @bind="Name">
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-file-code"></i>
</span>
</div>
<DataAnnotationsValidator />
<p class="help">Give a name coherently to the service which is going to run behind</p>
</div>
</EditForm>
</div>
<div class="modal-card-foot">
<div class="level fullwidth">
<div class="level-left">
<div class="level-item">
<button type="button" class="button is-rounded neoBtnSmall is-small has-text-dark" @onclick="Cancel">
<span class="icon is-small">
<i class="mdi mdi-close"></i>
</span>
<span>Close</span>
</button>
</div>
</div>
<div class="level-right">
<div class="level-item">
<button type="submit" class="button is-primary is-rounded neoBtnSmall is-small has-text-dark" @onclick="SubmitForm">
<span class="icon is-small">
<i class="mdi mdi-pen"></i>
</span>
<span>Rename</span>
</button>
</div>
</div>
</div>
</div>
</div>
@code {
[CascadingParameter]
BlazoredModalInstance BlazoredModal { get; set; }
[Required, Parameter, MaxLength(251)]
public string Name { get; set; }
void SubmitForm() => BlazoredModal.Close(ModalResult.Ok(Name));
void Cancel() => BlazoredModal.Cancel();
}

@ -48,7 +48,6 @@ namespace Seenginx
services.AddTransient<IDmesgService, DmesgService>();
services.AddTransient<INginxService, NginxService>();
services.AddTransient<ISystemDService, SystemDService>();
services.AddTransient<IFileManager, FileManager>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

File diff suppressed because one or more lines are too long

@ -106,6 +106,10 @@ html {
background: none !important;
border: none !important;
transform: scale(1.1); }
.neoBtnSmallPlain {
box-shadow: -2px -2px 4px rgba(251, 238, 208, 0.5), 2px 2px 4px rgba(241, 185, 65, 0.5);
background: none !important;
border: none !important; }
.neoFile {
box-shadow: 0px 0px 0px rgba(251, 238, 208, 0.5), 0px 0px 0px rgba(241, 185, 65, 0.5) !important;

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save