Implemented adding nginx conf file

This commit is contained in:
Eugene ;) 2020-07-01 19:36:22 +02:00
parent 665357421a
commit 1d173f2467
19 changed files with 317 additions and 80 deletions

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
@ -7,9 +7,9 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components" Version="3.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="3.1.3" />
<PackageReference Include="Radzen.Blazor" Version="2.5.8" />
<PackageReference Include="Microsoft.AspNetCore.Components" Version="3.1.5" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="3.1.5" />
<PackageReference Include="Radzen.Blazor" Version="2.10.9" />
</ItemGroup>

View File

@ -7,5 +7,7 @@ namespace Seenginx.Models
public class NewFileForm
{
public string Name { get; set; }
public string SelectedTemplate { get; set; } = "0";
public List<Template> Templates { get; set; } = new List<Template>();
}
}

View File

@ -0,0 +1,8 @@
namespace Seenginx.Models
{
public class Template
{
public string Name { get; set; }
public string Code { get; set; }
}
}

View File

@ -11,8 +11,8 @@
</span>
</div>
<div class="control has-icons-left">
<div class="select is-small is-rounded">
<select class="neoInput" @onchange="e => OnFilterClick(e.Value.ToString())">
<div class="select is-small is-rounded neoSelect">
<select @onchange="e => OnFilterClick(e.Value.ToString())">
@foreach (var filter in Filters)
{
<option value="@filter">@filter</option>
@ -57,8 +57,8 @@
<div class="filesList">
@foreach (var file in Files)
{
<div @onclick="e => OnFileClick(e,file)" @key="file" class="confFile borderRSmall isFinger neoFile @file.IsVisible @file.IsSelected">
<p class="is-7">@file.Folder</p>
<div @onclick="async e => await OnFileClick(e,file)" @key="file" class="confFile borderRSmall isFinger neoFile @file.IsVisible @file.IsSelected">
<p class="is-size-7">@file.Folder</p>
<p class="has-text-weight-bold ellipsis @(file.CanBeDeleted ? null : "has-text-danger")">@file.Name</p>
</div>
}
@ -77,13 +77,13 @@
<div class="buttons is-centered">
<button class="button is-rounded neoBtnSmall is-small noBottomMargin" @onclick="OnAddDialog">
<span class="icon is-small has-text-success">
<i class="mdi mdi-plus-box-outline"></i>
<i class="mdi mdi-plus"></i>
</span>
<span>Add</span>
</button>
<button class="button is-rounded neoBtnSmall is-small noBottomMargin @IsSelectedFileDeletable" @onclick="OnDeleteDialog">
<span class="icon is-small has-text-danger">
<i class="mdi mdi-minus-box-outline"></i>
<i class="mdi mdi-minus"></i>
</span>
<span>Delete</span>
</button>

View File

@ -51,26 +51,39 @@ namespace Seenginx.Components
[Parameter]
public CFile SelectedFile { get; set; } = default;
protected async override Task OnInitializedAsync()
protected override async Task OnParametersSetAsync()
{
SelectedFilter = Filters.First();
await base.OnInitializedAsync();
try
{
SelectedFilter = Filters.FirstOrDefault();
await base.OnParametersSetAsync();
}
catch (Exception ex)
{
throw ex;
}
}
protected async override Task OnAfterRenderAsync(bool firstRender)
{
try
{
await JsRuntime.InvokeVoidAsync("InitEditor");
await base.OnAfterRenderAsync(firstRender);
}
catch (Exception ex)
{
throw ex;
}
}
protected async Task OnFilterClick(string filter)
protected void OnFilterClick(string filter)
{
SelectedFilter = filter;
SearchFile();
}
protected async Task SearchInputChanged(string searchInput)
protected void SearchInputChanged(string searchInput)
{
SearchInput = searchInput;
SearchFile();
@ -169,8 +182,6 @@ namespace Seenginx.Components
[Parameter]
public EventCallback AddFileModal { get; set; }
[Parameter]
public Result<ConfigFile> AddResult { get; set; }
protected async Task OnAddDialog()
{
await AddFileModal.InvokeAsync(null);

View File

@ -1,33 +1,74 @@
@inherits NginxBase
@page "/nginx"
<FilesWithEditor CFile="ConfigFile" Filters="Filters" Files="ConfigFiles" FilterFolder="FilterFolder"
SelectedFile="SelectedFile" SelectedFileChanged="SelectedFileChanged"
TestConfiguration="TestConfiguration" TestResult="TestResult"
DeleteFileModal="DeleteFile" DeleteResult="DeleteResult"
AddFileModal="ShowAddFileModal" AddResult="AddFileResult">
AddFileModal="ShowAddFileModal">
</FilesWithEditor>
<Modal @ref="AddFileModal">
<ModalBackdrop />
<ModalContent IsForm="true" IsCentered="true">
<ModalContent Class="neomorph">
<ModalHeader>
<ModalTitle>Add new file form</ModalTitle>
<CloseButton Clicked="e => CloseModal(AddFileModal)"/>
<ModalTitle Class="has-text-centered">Add a new configuration for a service</ModalTitle>
</ModalHeader>
<ModalBody>
<Blazorise.Bulma.Fields>
<Blazorise.Bulma.Field>
<Blazorise.Bulma.FieldLabel>File name</Blazorise.Bulma.FieldLabel>
<Blazorise.Bulma.FieldBody @bind-FileName="NewFileForm.Name"></Blazorise.Bulma.FieldBody>
<Blazorise.Bulma.FieldHelp>Service name which is going to be behing di config file</Blazorise.Bulma.FieldHelp>
</Blazorise.Bulma.Field>
</Blazorise.Bulma.Fields>
<div class="field">
<label class="label">Template</label>
<div class="control has-icons-left">
<div class="select is-small is-rounded neoSelect fullwidth">
<select class="fullwidth" @bind="NewFileForm.SelectedTemplate">
<option value="0">No template</option>
@foreach (var template in NewFileForm.Templates)
{
<option value="@template.Name">@($"{template.Name.First().ToString().ToUpper()}{template.Name.Substring(1)}")</option>
}
</select>
</div>
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-puzzle-outline"></i>
</span>
</div>
<p class="help">Any template to quick setup the configuration</p>
</div>
<div class="field">
<label class="label">Configuration file name</label>
<div class="control has-icons-left has-icons-right">
<input class="input is-rounded is-small neoInput" type="text" @bind="NewFileForm.Name" placeholder="Name" />
<span class="icon is-small is-left has-text-dark">
<i class="mdi mdi-file-code-outline"></i>
</span>
</div>
<p class="help">Name it the same as the service which is going to run behind</p>
</div>
</ModalBody>
<ModalFooter>
<Blazorise.Bulma.Button Color="Color.Secondary" Clicked="e => CloseModal(AddFileModal)">Close</Blazorise.Bulma.Button>
<Blazorise.Bulma.Button Color="Color.Primary" Clicked="AddFileAsync">Add</Blazorise.Bulma.Button>
<div class="level fullwidth">
<div class="level-left">
<div class="level-item">
<Blazorise.Bulma.Button Clicked="e => CloseModal(AddFileModal)"
Class="is-rounded neoBtnSmall is-small has-text-dark">
<span class="icon is-small">
<i class="mdi mdi-close"></i>
</span>
<span>Close</span>
</Blazorise.Bulma.Button>
</div>
</div>
<div class="level-right">
<div class="level-item">
<Blazorise.Bulma.Button Color="Color.Primary" Clicked="AddFileAsync"
Class="is-rounded neoBtnSmall is-small has-text-dark" Type="ButtonType.Submit">
<span class="icon is-small has-text-success">
<i class="mdi mdi-plus"></i>
</span>
<span>Add</span>
</Blazorise.Bulma.Button>
</div>
</div>
</div>
</ModalFooter>
</ModalContent>
</Modal>
<GeneralNotificationModal ModalReference="GeneralNotificationModal"
NotificationSettings="GeneralNotificationSettings"></GeneralNotificationModal>
@*<GeneralNotificationModal ModalReference="GeneralNotificationModal" NotificationSettings="GeneralNotificationSettings"></GeneralNotificationModal>*@

View File

@ -30,7 +30,9 @@ namespace Seenginx.Pages
public Dictionary<string, string> FilterFolder { get; set; } = new Dictionary<string, string>();
protected override async Task OnInitializedAsync()
protected override async Task OnParametersSetAsync()
{
try
{
ConfigFiles.AddRange(await NginxService.GetFilesAsync());
Filters.AddRange(new List<string> { "All", "Root", "Conf.d", "Available", "Enabled" });
@ -39,38 +41,51 @@ namespace Seenginx.Pages
FilterFolder.Add("Conf.d", "/conf.d");
FilterFolder.Add("Available", "/sites-available");
FilterFolder.Add("Enabled", "/sites-enabled");
await base.OnInitializedAsync();
NewFileForm.Templates.AddRange(await NginxService.GetTemplates());
}
catch (Exception ex)
{
throw ex;
}
await base.OnParametersSetAsync();
}
public async Task SelectedFileChanged(ConfigFile configFile)
public void SelectedFileChanged(ConfigFile configFile)
{
SelectedFile = configFile;
}
protected Modal AddFileModal { get; set; }
public Result<ConfigFile> AddFileResult { get; set; }
public async Task ShowAddFileModal()
public void ShowAddFileModal()
{
AddFileModal.Show();
}
public NewFileForm NewFileForm { get; set; } = new NewFileForm();
public async Task AddFileAsync()
{
AddFileResult = await NginxService.AddFileAsync(NewFileForm);
if (AddFileResult.AllOk)
ConfigFiles.Add(AddFileResult.Data);
else
{
GeneralNotificationSettings = new GeneralNotificationSettings
{
ButtonColor = Color.Danger,
TitleClass = "mdi-error",
Title = "Failure",
Text = TestResult.ErrorMessage
};
GeneralNotificationModal.Show();
}
var addFileResult = await NginxService.AddFileAsync(NewFileForm);
if (!addFileResult.AllOk)
throw new Exception(":/");
ConfigFiles.Add(addFileResult.Data);
ConfigFiles = ConfigFiles.OrderBy(cf => cf.Name).ToList();
AddFileModal.Hide();
//if (AddFileResult.AllOk)
// ConfigFiles.Add(AddFileResult.Data);
//else
//{
// GeneralNotificationSettings = new GeneralNotificationSettings
// {
// ButtonColor = Color.Danger,
// TitleClass = "mdi-error",
// Title = "Failure",
// Text = TestResult.ErrorMessage
// };
// GeneralNotificationModal.Show();
//}
}
public Result<ConfigFile> SaveUpdateDraftResult { get; set; }

View File

@ -52,3 +52,32 @@ html {
}
}
.modal- {
&background {
background: rgba($background,.9);
}
&content {
border-radius: $border-radius-b;
}
&card- {
&head, &foot {
background: $background
}
&head {
border: none;
border-radius: 0;
}
&body {
background: $background
}
&foot {
border: none;
border-radius: 0;
}
}
}

View File

@ -50,11 +50,6 @@
min-height: 10%;
padding: 4% 0;
& .confFile {
padding: 4% 6%;
margin-bottom: 3%;
}
&List {
display: flex;
flex-direction: column;
@ -96,3 +91,11 @@
.menu-list > li > .neoFile {
margin-bottom: 4%
}
.confFile {
padding: 4% 6%;
margin-bottom: 3%;
}

View File

@ -137,6 +137,16 @@
border: none !important;
}
}
&Select > select {
box-shadow: inset 2px 2px 4px rgba($dark-shadow, .5),inset -2px -2px 4px rgba($light-shadow, .5) !important;
background: $background !important;
border: none !important;
&:focus {
border: none !important;
}
}
}
.gradientBackground {
@ -168,3 +178,7 @@
overflow: hidden;
text-overflow: ellipsis;
}
.fullwidth {
width: 100%
}

View File

@ -10,6 +10,7 @@
<ItemGroup>
<Folder Include="wwwroot\images\" />
<Folder Include="wwwroot\templates\systemd\" />
</ItemGroup>
<ItemGroup>
@ -17,10 +18,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Blazorise.Bulma" Version="0.9.0.1" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.3" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.2" />
<PackageReference Include="Blazorise.Bulma" Version="0.9.1.1" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.5" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.3" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
</ItemGroup>

View File

@ -10,6 +10,7 @@ namespace Seenginx.Services
{
public async Task<IEnumerable<string>> GetLogMessages(DmesgFilter filter = null)
{
await Task.Run(() => { });
return new List<string>();
}
}

View File

@ -9,5 +9,6 @@ namespace Seenginx.Services
Task<IEnumerable<ConfigFile>> GetFilesAsync();
Task<Result<string>> TestNginxConfigurations(ConfigFile configFile);
Task<Result<ConfigFile>> AddFileAsync(NewFileForm newFileForm);
Task<IEnumerable<Template>> GetTemplates();
}
}

View File

@ -1,9 +1,11 @@
using Microsoft.CodeAnalysis;
using Seenginx.Models;
using Seenginx.Services.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Seenginx.Services
@ -19,13 +21,25 @@ namespace Seenginx.Services
public async Task<Result<ConfigFile>> AddFileAsync(NewFileForm newFileForm)
{
await Task.Run(() => { });
var newFile = new ConfigFile();
newFile.Name = $"{newFileForm.Name}.conf";
newFile.Folder = "/conf.d";
newFile.FullPath = Path.Combine(ConfigPaths.NginxPath, "conf.d", newFile.Name);
newFile.Body = newFileForm.SelectedTemplate == 0.ToString() ? string.Empty : (await GetTemplates()).SingleOrDefault(t => t.Name == newFileForm.SelectedTemplate)?.Code;
newFile.LastUpdated = DateTime.UtcNow;
await File.WriteAllTextAsync(newFile.FullPath, newFile.Body, Encoding.UTF8);
var addResult = new Result<ConfigFile>();
addResult.Data.Name = newFileForm.Name;
addResult.SetData(newFile);
return addResult;
}
public async Task<IEnumerable<ConfigFile>> GetFilesAsync()
{
await Task.Run(() => { });
var rootConfigs = Directory.GetFiles(ConfigPaths.NginxPath, "*.conf");
var confdConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "conf.d"), "*.conf");
var sitesAvailableConfigs = Directory.GetFiles(Path.Combine(ConfigPaths.NginxPath, "sites-available"), "*.conf");
@ -88,8 +102,36 @@ namespace Seenginx.Services
return finalList;
}
public async Task<IEnumerable<Template>> GetTemplates()
{
var templates = new List<Template>();
try
{
var nginxTemplateDirectory = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "templates", "nginx");
//var systemdTemplateDirectory = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "systemd");
var nginxTemplateFiles = Directory.GetFiles(nginxTemplateDirectory, "*.template");
//var systemdTemplateFiles = 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<string>> TestNginxConfigurations(ConfigFile configFile)
{
await Task.Run(() => { });
var result = new Result<string>();
result.SetData("Uhu");
return result;

View File

@ -10,11 +10,13 @@ namespace Seenginx.Services
{
public async Task<IEnumerable<ConfigFile>> GetFiles(SystemDFilter filter = null)
{
await Task.Run(() => { });
return new List<ConfigFile>();
}
public async Task<IEnumerable<string>> GetLogMessages(SystemDLogsFilter filter = null)
{
await Task.Run(() => { });
return new List<string>();
}
}

View File

@ -25,8 +25,6 @@ namespace Seenginx
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages()
@ -67,8 +65,7 @@ namespace Seenginx
app.UseRouting();
app.ApplicationServices
.UseBulmaProviders();
app.ApplicationServices.UseBulmaProviders();
app.UseAuthentication();

View File

@ -126,6 +126,13 @@ html {
.neoInput:focus {
border: none !important; }
.neoSelect > select {
box-shadow: inset 2px 2px 4px rgba(241, 185, 65, 0.5), inset -2px -2px 4px rgba(251, 238, 208, 0.5) !important;
background: #f6d287 !important;
border: none !important; }
.neoSelect > select:focus {
border: none !important; }
.gradientBackground {
background: linear-gradient(to right bottom, #f7d794, #f5cd79); }
@ -147,6 +154,9 @@ html {
overflow: hidden;
text-overflow: ellipsis; }
.fullwidth {
width: 100%; }
@font-face {
font-family: 'Ubuntu';
src: url(/fonts/ubuntu-light-webfont.woff2) format("woff2");
@ -187,6 +197,26 @@ html {
.ace-solarized-light .ace_marker-layer .ace_active-line {
border-radius: 0 50px 50px 0; }
.modal-background {
background: rgba(246, 210, 135, 0.9); }
.modal-content {
border-radius: 28px; }
.modal-card-head, .modal-card-foot {
background: #f6d287; }
.modal-card-head {
border: none;
border-radius: 0; }
.modal-card-body {
background: #f6d287; }
.modal-card-foot {
border: none;
border-radius: 0; }
:root {
--stripe-size: 200px;
--color1: #f6d287;
@ -284,9 +314,6 @@ html {
display: block;
min-height: 10%;
padding: 4% 0; }
.filesWithEditor .files .confFile {
padding: 4% 6%;
margin-bottom: 3%; }
.filesWithEditor .filesList {
display: flex;
flex-direction: column;
@ -316,3 +343,7 @@ html {
.menu-list > li > .neoFile {
margin-bottom: 4%; }
.confFile {
padding: 4% 6%;
margin-bottom: 3%; }

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,39 @@
Proxy
server {
server_name <domain name>;
listen 80;
listen [::]:80;
location / {
return 301 https://$host$request_uri;
}
}
server {
server_name <domain name>;
listen 443 ssl http2;
#listen [::]:443 ssl http2;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-Robots-Tag "none";
add_header X-Download-Options "noopen";
add_header X-Permitted-Cross-Domain-Policies "none";
add_header X-XSS-Protection "1;mode=block";
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains";
add_header Referrer-Policy "no-referrer";
client_max_body_size 1G;
location / {
proxy_http_version 1.1;
proxy_pass_request_headers on;
proxy_set_header Connection "keep-alive";
proxy_store off;
proxy_pass http://localhost:<service port>;
gzip on;
gzip_proxied any;
gzip_types *;
}
#ssl_certificate /etc/letsencrypt/live/<domain name>/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/<domain name>/privkey.pem;
}