PHP Classes

File: FrontEndScripts/Controllers/SiteEditorController.ts

Recommend this page to a friend!
  Classes of Aleksey Nemiro   PHP Small Server Administrator   FrontEndScripts/Controllers/SiteEditorController.ts   Download  
File: FrontEndScripts/Controllers/SiteEditorController.ts
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: PHP Small Server Administrator
Web panel for small Debian and Ubuntu servers
Author: By
Last change:
Date: 7 years ago
Size: 48,492 bytes
 

Contents

Class file image Download
?/* * Copyright © Aleksey Nemiro, 2016. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ module SmallServerAdmin.Controllers { export class SiteEditorController implements Nemiro.IController { //#region ..properties.. private LevelsList = ['Nginx', 'Apache', 'HTAN']; public Scope: any; public Context: Nemiro.AngularContext; /** SSA config. */ public get Config(): Models.Config { return this.Scope.$parent.Config; } /** The site data. */ public get Site(): Models.Site { return this.Scope.Site; } public set Site(value: Models.Site) { this.Scope.Site = value; } /** * The source site name. */ public get SourceName(): string { return this.Scope.SourceName; } public set SourceName(value: string) { this.Scope.SourceName = value; } /** Loading indicator. */ public get Loading(): boolean { return this.Scope.Loading; } public set Loading(value: boolean) { this.Scope.Loading = value; } public get Saving(): boolean { return this.Scope.Saving; } public set Saving(value: boolean) { this.Scope.Saving = value; } /** Reloading indicator. */ public get Reloading(): boolean { return this.Scope.Reloading; } public set Reloading(value: boolean) { this.Scope.Reloading = value; } /** Gets or sets reloading items. */ public get ReloadingItems(): Array<Models.ReloadingInfo> { return this.Scope.ReloadingItems; } public set ReloadingItems(value: Array<Models.ReloadingInfo>) { this.Scope.ReloadingItems = value; } /** Success result indicator. */ public get Success(): boolean { return this.Scope.Success; } public set Success(value: boolean) { this.Scope.Success = value; } public get EditorChanged(): boolean { return this.Scope.EditorChanged; } public set EditorChanged(value: boolean) { this.Scope.EditorChanged = value; //console.log('EditorChanged', value); if (value) { var $this = this; this.Context.Timeout(() => { $this.Scope.EditorChanged = false; //console.log('EditorChanged', $this.Scope.EditorChanged); }, 500); } } /** * Selectec config to delete. */ public get SelectecConfToDelete(): Models.SiteConf { return this.Scope.SelectecConfToDelete; } public set SelectecConfToDelete(value: Models.SiteConf) { this.Scope.SelectecConfToDelete = value; } public get CreateNew(): Models.SiteNew { return this.Scope.CreateNew; } public set CreateNew(value: Models.SiteNew) { this.Scope.CreateNew = value; } public get CreateNewNginx(): Models.SiteNewNginx { return this.Scope.CreateNewNginx; } public set CreateNewNginx(value: Models.SiteNewNginx) { this.Scope.CreateNewNginx = value; } public get CreateNewApache(): Models.SiteNewApache { return this.Scope.CreateNewApache; } public set CreateNewApache(value: Models.SiteNewApache) { this.Scope.CreateNewApache = value; } public get CreateNewHTAN(): Models.SiteNewHTAN { return this.Scope.CreateNewHTAN; } public set CreateNewHTAN(value: Models.SiteNewHTAN) { this.Scope.CreateNewHTAN = value; } public get ActiveTab(): any { return this.Scope.ActiveTab; } public set ActiveTab(value: any) { this.Scope.ActiveTab = value; } public get CanAddConf(): boolean { return this.Scope.CanAddConf; } public set CanAddConf(value: boolean) { this.Scope.CanAddConf = value; } public get Folders(): Array<Models.FileSystemItem> { return this.Scope.Folders; } public set Folders(value: Array<Models.FileSystemItem>) { this.Scope.Folders = value; } public get SelectedFolder(): Models.FileSystemItem { return this.Scope.SelectedFolder; } public set SelectedFolder(value: Models.FileSystemItem) { this.Scope.SelectedFolder = value; } public get SelectFolderTarget(): ISelectPath { return this.Scope.SelectFolderTarget; } public set SelectFolderTarget(value: ISelectPath) { this.Scope.SelectFolderTarget = value; } public get SelectedFolderToDelete(): Models.FileSystemItem { return this.Scope.SelectedFolderToDelete; } public set SelectedFolderToDelete(value: Models.FileSystemItem) { this.Scope.SelectedFolderToDelete = value; } public get NewFolderName(): string { return this.Scope.NewFolderName; } public set NewFolderName(value: string) { this.Scope.NewFolderName = value; } public get NewFolderOwnerName(): string { return this.Scope.NewFolderOwnerName; } public set NewFolderOwnerName(value: string) { this.Scope.NewFolderOwnerName = value; } public get CreationFolder(): boolean { return this.Scope.CreationFolder; } public set CreationFolder(value: boolean) { this.Scope.CreationFolder = value; } public get AvailableLevels(): Array<string> { return this.Scope.AvailableLevels; } public set AvailableLevels(value: Array<string>) { this.Scope.AvailableLevels = value; } public get SelectedConfToAdd(): string { return this.Scope.SelectedConfToAdd; } public set SelectedConfToAdd(value: string) { this.Scope.SelectedConfToAdd = value; } public get Help(): any { return this.Scope.Help; } public set Help(value: any) { this.Scope.Help = value; } private ConfirmDeleteConfDialog: Nemiro.UI.Dialog; private CreateConfigDialog: Nemiro.UI.Dialog; private SelectFolderDialog: Nemiro.UI.Dialog; private CreateFolderDialog: Nemiro.UI.Dialog; private ConfirmToDeleteFolder: Nemiro.UI.Dialog; private ReloadingDialog: Nemiro.UI.Dialog; //#endregion //#region ..constructor.. constructor(context: Nemiro.AngularContext) { var $this = this; $this.Context = context; $this.Scope = $this.Context.Scope; $this.SelectedFolder = undefined; $this.Help = { IsOpened: false }; $this.LevelsList = ['Nginx']; if ($this.Config.WebServer.indexOf('apache') != -1) { $this.LevelsList.push('Apache'); } if ($this.Config.HtanEnabled) { $this.LevelsList.push('HTAN'); } $this.ConfirmDeleteConfDialog = Nemiro.UI.Dialog.CreateFromElement($('#confirmToDeleteConf')); $this.ConfirmToDeleteFolder = Nemiro.UI.Dialog.CreateFromElement($('#confirmToDeleteFolder')); $this.CreateConfigDialog = Nemiro.UI.Dialog.CreateFromElement($('#createConfig')); $this.SelectFolderDialog = Nemiro.UI.Dialog.CreateFromElement($('#selectFolder')); $this.CreateFolderDialog = Nemiro.UI.Dialog.CreateFromElement($('#createFolder')); $this.CreateFolderDialog.DisableOverlayClose = true; $this.ReloadingDialog = Nemiro.UI.Dialog.CreateFromElement($('#reloading')); $this.ReloadingDialog.DisableOverlayClose = true; $this.ReloadingDialog.DisplayCloseButton = true; $this.Scope.Create = () => { $this.Create($this); } $this.Scope.ShowSelectFolder = (target: ISelectPath) => { $this.SelectFolderTarget = target; $this.Folders = new Array<Models.FileSystemItem>(); $this.SelectedFolder = undefined; $this.GetFolders($this); $this.SelectFolderDialog.Show(); } $this.Scope.CreateDefault = () => { $this.CreateDefault($this); } $this.Scope.ConfirmDeleteConf = (item: Models.SiteConf) => { $this.SelectecConfToDelete = item; $this.ConfirmDeleteConfDialog.Show(); } $this.Scope.DeleteConf = () => { $this.DeleteConf($this); } $this.Scope.SelectConfToAdd = (level: string) => { $this.SelectedConfToAdd = level; } $this.Scope.PrepareAddConf = () => { $this.PrepareAddConf($this); } $this.Scope.ReinitCurrentConf = () => { if ($this.SelectedConfToAdd === undefined || $this.SelectedConfToAdd == null || $this.SelectedConfToAdd == '') { return; } $this['CreateNew' + $this.SelectedConfToAdd] = null; $this.PrepareAddConf($this); } $this.Scope.AddConf = () => { $this.AddConf($this); } $this.Scope.ConfEnabledClick = (item: Models.SiteConf) => { //console.log('ConfEnabledClick', item); item.Enabled = !item.Enabled; } $this.Scope.SelectNginxEventLog = (value: number) => { $this.CreateNewNginx.EventLogs = value; } $this.Scope.SelectApacheEventLog = (value: number) => { $this.CreateNewApache.EventLogs = value; } $this.Scope.TabClick = (tab: string) => { $this.ActiveTab = {}; $this.ActiveTab[tab] = true; $this.EditorChanged = true; } $this.Scope.ToggleFolder = (node: Models.FileSystemItem, expanded) => { //console.log('ToggleFolder', node, expanded); if (expanded && (node.Children == undefined || node.Children == null)) { if (node.Loading === undefined || !node.Loading) { $this.GetFolders($this, node); } } else if (!expanded) { node.Children = null; } } $this.Scope.ShowSelectedFolder = (node: Models.FileSystemItem, selected, $parentNode: Models.FileSystemItem) => { $this.SelectedFolder = node; $this.SelectedFolder.Parent = $parentNode; //$this.CreateNew.RootPath = node.Path; } $this.Scope.SelectFolderOptions = { isLeaf: (node: Models.FileSystemItem) => { return false; }, isSelectable: (node: Models.FileSystemItem) => { return node.Loading === undefined || !node.Loading; }, nodeChildren: 'Children' }; $this.Scope.ShowCreateFolder = () => { //$this.SelectFolderDialog.Close(); $this.NewFolderName = ''; $this.CreateFolderDialog.Show(); } $this.Scope.CreateFolder = () => { $this.CreateFolder($this); } $this.Scope.RenameFolder = (node: Models.FileSystemItem) => { $this.RenameFolder($this, node); } $this.Scope.ShowConfirmToDeleteFolder = (node: Models.FileSystemItem) => { $this.SelectedFolderToDelete = node; $this.ConfirmToDeleteFolder.Show(); } $this.Scope.DeleteFolder = () => { $this.DeleteFolder($this); } $this.Scope.SelectPath = () => { $this.SelectFolderTarget.SelectedPath = $this.SelectedFolder.Path; $this.SelectFolderDialog.Close(); } $this.Scope.Save = (needReloading: boolean) => { $this.Save($this, needReloading); } $this.Scope.SiteStatusChanged = () => { console.log('SiteStatusChanged'); if ($this.Site.IsEnabled && $this.AvailableLevels.indexOf('Nginx') == -1) { for (var i = 0; i < $this.Site.Conf.length; i++) { if ($this.Site.Conf[i].Level == 'Nginx') { $this.Site.Conf[i].Enabled = true; return; } } } } // load site $this.Load($this); } //#endregion //#region ..methods.. /** * Loads site data from the server. */ private Load($this: SiteEditorController): void { $this = $this || this; $this.Loading = true; if ($this.Context.Location.search().name === undefined || $this.Context.Location.search().name == null || $this.Context.Location.search().name == '') { $this.Loading = false; $this.CreateNew = new Models.SiteNew(); $this.CreateConfigDialog.Show(); return; } $this.CreateNew = null; // create request var apiRequest = new ApiRequest<Models.Site>($this.Context, 'Sites.GetSite', { name: $this.Context.Location.search().name }); // handler successful response to a request to api apiRequest.SuccessCallback = (response) => { $this.Scope.TabClick(response.data.Conf[0].Level); $this.Site = response.data; $this.SourceName = $this.Site.Name; $this.UpdateCanAddConf($this); }; apiRequest.CompleteCallback = () => { $this.Loading = false; } // execute apiRequest.Execute(); } private DeleteConf($this: SiteEditorController): void { $this.Site.Levels.splice($this.Site.Levels.indexOf($this.SelectecConfToDelete.Level), 1); $this.Site.Conf.splice($this.Site.Conf.indexOf($this.SelectecConfToDelete), 1); $this.ConfirmDeleteConfDialog.Close(); $this.SelectecConfToDelete = null; $this.UpdateCanAddConf($this); } private Create($this: SiteEditorController): void { console.log('Create'); $this.Site = new Models.Site(); $this.Site.Name = $this.CreateNew.Domain; $this.Site.IsEnabled = true; $this.Site.Levels = new Array<string>(); $this.Site.Conf = new Array<Models.SiteConf>(); // nginx $this.SelectedConfToAdd = 'Nginx'; $this.CreateNewNginx = new Models.SiteNewNginx(); $this.CreateNewNginx.Domain = $this.CreateNew.Domain; $this.CreateNewNginx.SelectedPath = $this.CreateNew.SelectedPath; $this.CreateNewNginx.PhpMode = $this.CreateNew.PhpMode; $this.CreateNewNginx.AspNetMode = $this.CreateNew.AspNetMode; $this.CreateNewNginx.AspNetFastCgiProcessCount = $this.CreateNew.AspNetFastCgiProcessCount; $this.CreateNewNginx.AspNetSocket = $this.CreateNew.AspNetSocket; $this.AddConf($this); // apache if ($this.CreateNew.AspNetMode == 'MOD' || $this.CreateNew.PhpMode == 'MOD') { $this.SelectedConfToAdd = 'Apache'; $this.CreateNewApache = new Models.SiteNewApache(); $this.CreateNewApache.Domain = $this.CreateNew.Domain; $this.CreateNewApache.SelectedPath = $this.CreateNew.SelectedPath; if ($this.CreateNew.AspNetMode != 'Off') { $this.CreateNewApache.AspNetVersion = $this.CreateNew.AspNetVersion; $this.CreateNewApache.AspNetIOMapForAll = $this.CreateNew.AspNetIOMapForAll; $this.CreateNewApache.AspNetDebug = $this.CreateNew.AspNetDebug; } $this.AddConf($this); } // htan if ($this.CreateNew.AspNetMode == 'FASTCGI') { $this.SelectedConfToAdd = 'HTAN'; $this.CreateNewHTAN = new Models.SiteNewHTAN(); $this.CreateNewHTAN.Domain = $this.CreateNew.Domain; $this.CreateNewHTAN.SelectedPath = $this.CreateNew.SelectedPath; $this.CreateNewHTAN.FastCGI = new Array<Models.SiteHTANItem>(); var hostParts = $this.CreateNew.Domain.split('.'); if (hostParts.length > 1) { hostParts.pop(); } var hostFirst = hostParts.join('.'); var hostLast = (hostParts = $this.CreateNew.Domain.split('.'))[hostParts.length - 1]; var address = Nemiro.Utility.Replace(hostFirst, '\\.', '_') + '_aspnet'; if ($this.CreateNew.AspNetFastCgiProcessCount == 1) { if ($this.CreateNew.AspNetSocket == 'TCP') { address = '127.0.0.1:' + $this.Config.AspNetFastCgiPort; } else { address = 'unix:/tmp/' + $this.CreateNew.Domain; } } var item = new Models.SiteHTANItem(address); item.AspNetVersion = $this.CreateNew.AspNetVersion; item.Enabled = true; item.Socket = address; $this.CreateNewHTAN.FastCGI.push(item); $this.AddConf($this); } $this.Scope.TabClick('Nginx'); $this.CreateConfigDialog.Close(); } private CreateDefault($this: SiteEditorController): void { $this.Site = new Models.Site(); $this.Site.Name = 'New site'; $this.Site.IsEnabled = true; $this.Site.Levels = new Array<string>(); $this.Site.Conf = new Array<Models.SiteConf>(); // nginx $this.SelectedConfToAdd = 'Nginx'; $this.CreateNewNginx = new Models.SiteNewNginx(); $this.CreateNewNginx.Domain = $this.CreateNew.Domain; $this.CreateNewNginx.SelectedPath = $this.CreateNew.SelectedPath; $this.CreateNewNginx.PhpMode = $this.CreateNew.PhpMode; $this.CreateNewNginx.AspNetMode = $this.CreateNew.AspNetMode; $this.CreateNewNginx.AspNetFastCgiProcessCount = $this.CreateNew.AspNetFastCgiProcessCount; $this.CreateNewNginx.AspNetSocket = $this.CreateNew.AspNetSocket; $this.AddConf($this); $this.Scope.TabClick('Nginx'); } private GetFolders($this: SiteEditorController, parent?: Models.FileSystemItem): void { if ($this.Folders === undefined || $this.Folders == null || $this.Folders.length <= 0) { $this.Loading = true; } var path = '/'; if (parent !== undefined && parent != null) { path = parent.Path; parent.Loading = true; } // create request var apiRequest = new ApiRequest<Array<Models.FileSystemItem>>($this.Context, 'Sites.GetFolders', { path: path }); // handler successful response to a request to api apiRequest.SuccessCallback = (response) => { //$this.Context.Timeout(() => { if (parent === undefined || parent == null) { $this.Folders = response.data; } else { parent.Children = response.data; } //}); }; apiRequest.CompleteCallback = () => { $this.Loading = false; if (parent !== undefined && parent != null) { parent.Loading = false; } } // execute apiRequest.Execute(); } private CreateFolder($this: SiteEditorController): void { $this.CreationFolder = true; // create request var apiRequest = new ApiRequest<any>($this.Context, 'Sites.CreateFolder', { path: $this.SelectedFolder.Path, name: $this.NewFolderName, owner: $this.NewFolderOwnerName }); // handler successful response to a request to api apiRequest.SuccessCallback = (response) => { $this.GetFolders($this, $this.SelectedFolder); $this.CreateFolderDialog.Close(); }; apiRequest.CompleteCallback = () => { $this.CreationFolder = false; } // execute apiRequest.Execute(); } private RenameFolder($this: SiteEditorController, node: Models.FileSystemItem): void { node.Loading = true; // create request var apiRequest = new ApiRequest<any>($this.Context, 'Sites.RenameFolder', { path: node.Path, name: node.NewName }); // handler successful response to a request to api apiRequest.SuccessCallback = (response) => { node.Path = response.data.Path; node.Name = node.NewName; node.RenameMode = false; }; apiRequest.CompleteCallback = () => { node.Loading = false; } // execute apiRequest.Execute(); } private DeleteFolder($this: SiteEditorController): void { $this.SelectedFolderToDelete.Loading = true; // create request var apiRequest = new ApiRequest<any>($this.Context, 'Sites.DeleteFolder', { path: $this.SelectedFolderToDelete.Path }); // handler successful response to a request to api apiRequest.SuccessCallback = (response) => { $this.ConfirmToDeleteFolder.Close(); $this.GetFolders($this, $this.SelectedFolderToDelete.Parent); }; apiRequest.CompleteCallback = () => { $this.SelectedFolderToDelete.Loading = false; } // execute apiRequest.Execute(); } private Save($this: SiteEditorController, needReloading: boolean): void { if (Nemiro.Utility.NextInvalidField($('#siteForm'))) { return; } $this.Saving = true; // create request var apiRequest = new ApiRequest<any>($this.Context, 'Sites.SaveSite', { 'SourceName': $this.SourceName, 'Site': $this.Site, 'IsNew': $this.CreateNew != null }); // handler successful response to a request to api apiRequest.SuccessCallback = (response) => { $this.Context.Window.location.hash = '#?name=' + $this.Site.Name; $this.CreateNew = null; $this.Success = true; // reloading services if (needReloading) { // get services to reload $this.ReloadingItems = new Array<Models.ReloadingInfo>(); for (var i = 0; i < $this.Site.Conf.length; i++) { $this.ReloadingItems.push(new Models.ReloadingInfo($this.Site.Conf[i].Level)); if ($this.Site.Conf[i].Level == 'Nginx') { if ($this.Site.Conf[i].Source.indexOf('php') != -1) { $this.ReloadingItems.push(new Models.ReloadingInfo('PHP-FPM')); } } } $this.ReloadServices($this); } else { $this.Context.Timeout(() => { $this.Load($this); }); } }; apiRequest.CompleteCallback = () => { $this.Saving = false; } // execute apiRequest.Execute(); } private ReloadServices($this: SiteEditorController): void { if ($this.ReloadingItems === undefined || $this.ReloadingItems == null || $this.ReloadingItems.length <= 0) { Nemiro.UI.Dialog.Alert(App.Resources.NoServicesToReload, App.Resources.Error); return; } $this.Reloading = true; $this.ReloadingDialog.Show(); for (var i = 0; i < $this.ReloadingItems.length; i++) { $this.ReloadService($this, $this.ReloadingItems[i]); } } private ReloadService($this: SiteEditorController, reloadingItem: Models.ReloadingInfo): void { if (reloadingItem.Status != '' && reloadingItem.Status != 'Waiting') { console.log('Service "' + reloadingItem.Name + '" already processing.'); return; } console.log('Reloading "' + reloadingItem.Name + '"...'); reloadingItem.Status = 'Processing'; // create request var apiRequest = new ApiRequest<any>($this.Context, 'Sites.ReloadServices', { 'services': reloadingItem.Name }); // handler successful response to a request to api apiRequest.SuccessCallback = (response) => { reloadingItem.Status = 'Success'; }; apiRequest.ErrorCallback = (response) => { if (response.status == 502 || response.status == 504) { $this.Context.Timeout($this.WaitingServerResponse($this, reloadingItem), 1000); } else { var exceptionMessage = ApiRequest.GetExceptionMessage((<any>response).data); if (exceptionMessage != null) { exceptionMessage = '<pre>' + exceptionMessage + '</pre>'; } else { exceptionMessage = ''; } Nemiro.UI.Dialog.Alert(Nemiro.Utility.Format(App.Resources.CannotReloadService, [reloadingItem.Name]) + exceptionMessage, App.Resources.Error + ' ' + response.status); reloadingItem.Status = 'Error'; } } apiRequest.CompleteCallback = () => { $this.UpdateReloadingStatus($this); } // execute apiRequest.Execute(); } private WaitingServerResponse($this: SiteEditorController, reloadingItem: Models.ReloadingInfo): any { ApiRequest.Echo($this.Context, (response) => { if (response.status != 200) { Nemiro.UI.Dialog.Alert(Nemiro.Utility.Format(App.Resources.CannotReloadService, [reloadingItem.Name]), App.Resources.Error + ' ' + response.status); reloadingItem.Status = 'Error'; } else { reloadingItem.Status = 'Success'; } $this.UpdateReloadingStatus($this); }, 5); } private UpdateReloadingStatus($this: SiteEditorController): void { for (var i = 0; i < $this.ReloadingItems.length; i++) { if ($this.ReloadingItems[i].Status == '' || $this.ReloadingItems[i].Status == 'Waiting' || $this.ReloadingItems[i].Status == 'Processing') { $this.Reloading = true; return; } } $this.Reloading = false; } private PrepareAddConf($this: SiteEditorController): void { console.log('PrepareAddConf', $this.AvailableLevels); var host = '%DOMAIN HERE%'; var path = '%PATH HERE%'; if ($this.CreateNewNginx === undefined || $this.CreateNewNginx == null) { if ($this.AvailableLevels.indexOf('Apache') == -1) { // has apache, extract host and root path var r_host = /ServerName(\s+)(\S+)/i; var r_root = /DocumentRoot(\s+)(\S+)/i; var conf = $this.GetConf($this, 'Apache'); if (conf != null) { var arr = r_host.exec(conf); if (arr != null && arr.length >= 2 && arr[2] != '') { host = arr[2]; } arr = r_root.exec(conf); if (arr != null && arr.length >= 2 && arr[2] != '') { path = arr[2]; } } } if (host == '%DOMAIN HERE%' || host == '') { host = $this.Site.Name; } $this.CreateNewNginx = new Models.SiteNewNginx(); $this.CreateNewNginx.Domain = host; $this.CreateNewNginx.SelectedPath = path; } if ($this.CreateNewApache === undefined || $this.CreateNewApache == null) { if ($this.AvailableLevels.indexOf('Nginx') == -1) { // has nginx, extract host and root path var r_host = /server_name(\s+)([^;]+)/i; var r_root = /root(\s+)([^;]+)/i; var conf = $this.GetConf($this, 'Nginx'); if (conf != null) { // masked \# conf = conf.replace(/(\\\#)/g, String.fromCharCode(1)); // remove comments conf = conf.replace(/(\#([^\r\n]*))/g, ''); // restore \# conf = conf.replace(/\x01/g, '\#'); var arr = r_host.exec(conf); if (arr != null && arr.length >= 2 && arr[2] != '') { host = arr[2]; } arr = r_root.exec(conf); if (arr != null && arr.length >= 2 && arr[2] != '') { path = arr[2]; } } } if (host == '%DOMAIN HERE%' || host == '') { host = $this.Site.Name; } $this.CreateNewApache = new Models.SiteNewApache(); $this.CreateNewApache.Domain = host; $this.CreateNewApache.SelectedPath = path; } if ($this.CreateNewHTAN === undefined || $this.CreateNewHTAN == null) { var fastCgiList = new Array<Models.SiteHTANItem>(); if ($this.AvailableLevels.indexOf('Nginx') == -1) { var r_host = /server_name(\s+)([^;]+)/i; var r_root = /root(\s+)([^;]+)/i; var r_fastcgi_pass = /fastcgi_pass(\s+)([^;]+)/gi; var r_fastcgi_pass_sgl = /fastcgi_pass(\s+)([^;]+)/i; var conf = $this.GetConf($this, 'Nginx'); console.log('conf', conf); if (conf != null) { // masked \# conf = conf.replace(/(\\\#)/g, String.fromCharCode(1)); // remove comments conf = conf.replace(/(\#([^\r\n]*))/g, ''); // restore \# conf = conf.replace(/\x01/g, '\#'); var arr = r_host.exec(conf); if (arr != null && arr.length >= 2 && arr[2] != '') { host = arr[2]; } arr = r_root.exec(conf); if (arr != null && arr.length >= 2 && arr[2] != '') { path = arr[2]; } var arr2 = conf.match(r_fastcgi_pass); if (arr2 != null) { for (var i = 0; i < arr2.length; i++) { arr = r_fastcgi_pass_sgl.exec(arr2[i]); // console.log('fastcgi_pass', i, arr2[i], arr); fastCgiList.push(new Models.SiteHTANItem(arr[2])); } } console.log('fastCgiList', fastCgiList); } } if (host == '%DOMAIN HERE%' || host == '') { host = $this.Site.Name; } $this.CreateNewHTAN = new Models.SiteNewHTAN(); $this.CreateNewHTAN.Domain = host; $this.CreateNewHTAN.SelectedPath = path; $this.CreateNewHTAN.FastCGI = fastCgiList; } // only one available conf if ($this.AvailableLevels.length == 1) { // select it $this.SelectedConfToAdd = $this.AvailableLevels[0]; } else { if ($this.SelectedConfToAdd !== undefined && $this.SelectedConfToAdd != null && $this.SelectedConfToAdd != '' && $this.AvailableLevels.indexOf($this.SelectedConfToAdd) == -1) { $this.SelectedConfToAdd = ''; } } } private AddConf($this: SiteEditorController): void { console.log('AddConf', $this.SelectedConfToAdd, $this['CreateNew' + $this.SelectedConfToAdd]); if ($this.SelectedConfToAdd == 'Nginx') { var logPath = Nemiro.Utility.DirectoryName($this.CreateNewNginx.SelectedPath) + '/' + $this.Config.LogFolderName; var hostParts = $this.CreateNewNginx.Domain.split('.'); if (hostParts.length > 1) { hostParts.pop(); } var hostFirst = hostParts.join('.'); var hostLast = (hostParts = $this.CreateNewNginx.Domain.split('.'))[hostParts.length - 1]; var upstreams = ''; var conf = 'server {\n'; conf += ` root ${$this.CreateNewNginx.SelectedPath};` + '\n'; conf += ` server_name ${$this.CreateNewNginx.Domain};` + '\n'; if (($this.CreateNewNginx.EventLogs & 1) == 1) { conf += ` error_log ${logPath}/nginx_${$this.CreateNewNginx.Domain}_error.log error` + '\n'; } if (($this.CreateNewNginx.EventLogs & 2) == 2) { conf += ` access_log ${logPath}/nginx_${$this.CreateNewNginx.Domain}_access.log` + '\n'; } //conf += '\n'; //conf += ' location / {\n'; conf += ' index '; if ($this.CreateNewNginx.PhpMode != 'Off') { conf += 'index.php '; } if ($this.CreateNewNginx.AspNetMode != 'Off') { conf += 'Default.aspx Index.aspx '; } conf += 'index.html index.htm;\n'; //conf += ' }\n\n'; conf += '\n'; if ($this.CreateNewNginx.PhpMode != 'Off') { // PHP var upstreamName = Nemiro.Utility.Replace(hostFirst, '\\.', '_') + '_php'; conf += $this.MakeNginxPhpConf ( $this.CreateNewNginx.Domain, $this.CreateNewNginx.PhpMode, $this.CreateNewNginx.PhpFastCgiProcessCount, $this.CreateNewNginx.PhpSocket, upstreamName, $this.Config.PhpFastCgiPort ); conf += '\n'; if ($this.CreateNewNginx.PhpMode == 'FPM' && $this.CreateNewNginx.PhpFastCgiProcessCount > 1) { if (upstreams.length > 0) { upstreams += '\n'; } upstreams += $this.MakeNginxUpstream ( upstreamName, $this.CreateNewNginx.PhpFastCgiProcessCount, $this.CreateNewNginx.PhpSocket, (hostFirst + '-{0}.' + hostLast), $this.Config.PhpFastCgiPort ); } } if ($this.CreateNewNginx.AspNetMode != 'Off') { // ASP.NET var upstreamName = Nemiro.Utility.Replace(hostFirst, '\\.', '_') + '_aspnet'; conf += $this.MakeNginxAspNetConf ( $this.CreateNewNginx.Domain, $this.CreateNewNginx.AspNetMode, $this.CreateNewNginx.AspNetFastCgiProcessCount, $this.CreateNewNginx.AspNetSocket, upstreamName, $this.Config.AspNetFastCgiPort ); conf += '\n'; if ($this.CreateNewNginx.AspNetMode == 'FASTCGI' && $this.CreateNewNginx.AspNetFastCgiProcessCount > 1) { if (upstreams.length > 0) { upstreams += '\n'; } upstreams += $this.MakeNginxUpstream ( upstreamName, $this.CreateNewNginx.AspNetFastCgiProcessCount, $this.CreateNewNginx.AspNetSocket, (hostFirst + '-{0}.' + hostLast), $this.Config.AspNetFastCgiPort ); } } // other conf += ' # Static files caching\n'; conf += ' location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {\n'; conf += ' expires max;\n'; conf += ' log_not_found off;\n'; conf += ' access_log off;\n'; conf += ' }\n\n'; /* if ($this.CreateNewNginx.PhpMode != 'Off') { conf += ' # Disable viewing .htaccess and .htpassword\n'; conf += ' location ~ /\.ht {\n'; conf += ' deny all;\n'; conf += ' }\n\n'; } */ /* if ($this.CreateNewNginx.AspNetMode != 'Off') { conf += ' # disable viewing .config\n'; conf += ' location ~ /\.config {\n'; conf += ' deny all;\n'; conf += ' }\n\n'; }*/ // -- conf += '}'; if (upstreams.length > 0) { conf = upstreams + '\n' + conf; } $this.Site.Conf.push(new Models.SiteConf('Nginx', conf)); $this.Site.Levels.push('Nginx'); $this.CreateNewNginx = null; } else if ($this.SelectedConfToAdd == 'Apache') { var logPath = Nemiro.Utility.DirectoryName($this.CreateNewApache.SelectedPath) + '/' + $this.Config.LogFolderName; var conf = `<VirtualHost ${$this.Config.ApacheHost}:${$this.Config.ApachePort}>` + '\n'; conf += ` DocumentRoot ${$this.CreateNewApache.SelectedPath}` + '\n'; conf += ` ServerName ${$this.CreateNewApache.Domain}` + '\n'; if (($this.CreateNewApache.EventLogs & 1) == 1) { conf += ` ErrorLog ${logPath}/apache_${$this.CreateNewApache.Domain}_error.log error` + '\n'; } if (($this.CreateNewApache.EventLogs & 2) == 2) { conf += ` CustomLog ${logPath}/apache_${$this.CreateNewApache.Domain}_access.log` + ' common\n'; } if ($this.CreateNewApache.AspNetVersion != 'Off') { conf += '\n'; conf += $this.MakeApacheAspNetHeaders($this.CreateNewApache.AspNetVersion, $this.CreateNewApache.Domain, $this.CreateNewApache.SelectedPath, $this.CreateNewApache.AspNetIOMapForAll, $this.CreateNewApache.AspNetDebug); conf += '\n'; conf += $this.MakeApacheAspNetLocation($this.CreateNewApache.Domain); } else { conf += '\n'; conf += $this.MakeApacheDefaultLocation(); } // mono-ctrl if ($this.CreateNewApache.MonoCtrl) { conf += '\n'; conf += ' <Location /mono>\n'; conf += ' SetHandler mono-ctrl\n'; conf += ' AllowOverride All\n'; conf += ' Order Allow,Deny\n'; conf += ' Allow from all\n'; conf += ' Require all granted\n'; conf += ' </Location>\n'; } // svn if ($this.CreateNewApache.WebDavSvn) { conf += '\n'; conf += ' # You can specify custom home directory of site\n'; conf += ' # for browse list of repositories:\n'; conf += ' # <Directory /usr/share/svn-web>\n'; conf += ' # AllowOverride All\n'; conf += ' # Allow from all\n'; conf += ' # Require all granted\n'; conf += ' # </Directory>\n\n'; conf += ' <Location /svn>\n'; conf += ' DAV svn\n'; conf += ' # Enter the path where your repositories are located:\n'; conf += ' SVNParentPath /var/svn/\n'; conf += ' SVNListParentPath On\n'; conf += ' # You can make your own styles for browsing a repositories:\n'; conf += ' # SVNIndexXSLT /usr/share/svn-web/index.xsl\n\n'; conf += ' # If you want to restrict access, you can enable authorization:\n'; conf += ' # AuthType Basic\n'; conf += ' # AuthName "Subversion Repository"\n'; conf += ' # Enter the path to the password file\n'; conf += ' # AuthUserFile /etc/apache2/dav_svn.passwd\n'; conf += ' # Require valid-user\n\n'; conf += ' # Specify a file of access rules to the repositories:\n'; conf += ' # <IfModule mod_authz_svn.c>\n'; conf += ' # AuthzSVNAccessFile /etc/apache2/dav_svn.authz\n'; conf += ' # </IfModule>\n'; conf += ' </Location>\n'; } conf += '</VirtualHost>'; $this.Site.Conf.push(new Models.SiteConf('Apache', conf)); $this.Site.Levels.push('Apache'); $this.CreateNewApache = null; } else if ($this.SelectedConfToAdd == 'HTAN') { // get nginx config for parse upstreams var nginx = $this.GetConf($this, 'Nginx'); if (nginx != null) { // masked \# nginx = nginx.replace(/(\\\#)/g, String.fromCharCode(1)); // remove comments nginx = nginx.replace(/(\#([^\r\n]*))/g, ''); // restore \# nginx = nginx.replace(/\x01/g, '\#'); } // -- // make htan config var commands = '', items = ''; var commandKyes = [], commandNames = []; for (var i = 0; i < $this.CreateNewHTAN.FastCGI.length; i++) { var item = $this.CreateNewHTAN.FastCGI[i]; if (!item.Enabled) { continue; } // make command key and name var key = item.AspNetVersion + ';' + (item.User != 'root' ? item.User : '') + ';' + (item.Group != 'root' ? item.Group : ''); var name = 'command-' + (commandKyes.length + 1); // name for new command // search command by key if (commandKyes.indexOf(key) != -1) { // name for existing command name = commandNames[commandKyes.indexOf(key)]; } // make items if (item.Socket.indexOf(':') == -1) { // is upstream name, parse nginx if (nginx != null) { // extract upstream var upstream = new RegExp('upstream(\\s+)' + item.Socket + '(\\s*)\\{([^\\}]+?)\\}', 'm').exec(nginx); if (upstream == null) { if (items.length > 0) { items += '\n'; } items += ' <!--Error: Upstream "' + item.Socket + '" not found in the Nginx config-->'; } else { // parse addresses var arr = upstream[3].match(/server(\s+)([^\s\;]+)/g); if (arr == null) { items += ' <!--Error: Cannot parse upstream "' + item.Socket + '"-->'; } else { for (var j = 0; j < arr.length; j++) { if (items.length > 0) { items += '\n'; } items += ' <add address="' + /server(\s+)([^\s\;]+)/.exec(arr[j])[2] + '" command="' + name + '" />'; } } } } else { if (items.length > 0) { items += '\n'; } items += ' <!--Error: Nginx is required for upstream-->'; } } else { // single address if (items.length > 0) { items += '\n'; } items += ' <add address="' + item.Socket + '" command="' + name + '" />'; } if (commandKyes.indexOf(key) != -1) { continue; } // make command if (commands.length > 0) { commands += '\n'; } commands += ' <add\n'; commands += ' name="' + name + '"\n'; if (item.User != '') { commands += ' user="' + item.User + '"\n'; } if (item.Group != '') { commands += ' group="' + item.Group + '"\n'; } var exec = '/usr/bin/fastcgi-mono-server4'; if (item.AspNetVersion == '1.0') { exec = '/usr/bin/fastcgi-mono-server'; } else if (item.AspNetVersion == '2.0') { exec = '/usr/bin/fastcgi-mono-server2'; } commands += ' exec="' + exec + '"\n'; commands += ` arguments="/applications=/:${$this.CreateNewHTAN.SelectedPath} /socket={socket} /multiplex=True /verbose=True"` + '\n'; // /printlog=True commands += ' />'; // add command key and name to existing commands commandNames.push(name); commandKyes.push(key); } var conf = ''; conf += '<configuration>\n'; conf += ' <fastCGI>\n'; conf += items + '\n'; conf += ' </fastCGI>\n'; conf += ' <commands>\n'; conf += commands + '\n'; conf += ' </commands>\n'; conf += '</configuration>'; $this.Site.Conf.push(new Models.SiteConf('HTAN', conf)); $this.Site.Levels.push('HTAN'); $this.CreateNewHTAN = null; } $this.UpdateCanAddConf($this); $this.Scope.TabClick($this.Site.Conf[$this.Site.Conf.length - 1].Level); } private MakeNginxUpstream(name: string, processes: number, socket: string, unixName: string, port: number): string { var result = 'upstream ' + name + ' {'; for (var i = 0; i < processes; i++) { if (result.length > 0) { result += '\n'; } if (socket == 'TCP') { result += ' server 127.0.0.1:' + (port + i) + ';'; } else { result += ' server unix:/tmp/' + Nemiro.Utility.Format(unixName, [i + 1]) + ';'; } } result += '\n}\n'; return result; } private MakeNginxPhpConf(host: string, mode: string, processes: number, socket: string, upstream: string, port: number): string { var conf = ''; if (mode == 'FPM') { conf += ' # PHP-FPM\n'; conf += ' location ~ \\.php$ {\n'; if (processes == 1) { if (socket == 'TCP') { conf += ' fastcgi_pass 127.0.0.1:' + port.toString() + ';\n'; } else { conf += ' fastcgi_pass unix:/var/run/php5-fpm.sock;\n'; //TODO //unix:/tmp/' + host + ';\n'; } } else { conf += ' fastcgi_pass ' + upstream + ';\n'; } conf += ' fastcgi_index index.php;\n\n'; conf += ' include fastcgi_params;\n\n'; conf += ' fastcgi_split_path_info ^(.+\\.php)(/.+)$;\n'; conf += ' fastcgi_param PATH_INFO $fastcgi_path_info;\n'; conf += ' fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;\n'; conf += ' fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n'; conf += ' }\n'; } else { conf += ' # PHP to Apache\n'; conf += ' location ~ \\.php$ {\n'; conf += ' proxy_set_header X-Real-IP $remote_addr;\n'; conf += ' proxy_set_header X-Forwarded-For $remote_addr;\n'; conf += ' proxy_set_header Host $host;\n'; conf += ` proxy_pass http://${this.Config.ApacheHost}:${this.Config.ApachePort};` + '\n'; conf += ' }\n'; } return conf; } private MakeNginxAspNetConf(host: string, mode: string, processes: number, socket: string, upstream: string, port: number): string { var conf = ''; if (mode == 'FASTCGI') { conf += ' # ASP.NET FastCGI\n'; conf += ' location / {\n'; // ~ \.(aspx|asmx|ashx|axd|asax|ascx|cshtml|vbhtml|soap|rem|axd|cs|vb|config|dll)$ //conf += ' proxy_set_header X-Real-IP $remote_addr;\n'; //conf += ' proxy_set_header X-Forwarded-For $remote_addr;\n'; if (processes == 1) { if (socket == 'TCP') { conf += ' fastcgi_pass 127.0.0.1:' + port.toString() + ';\n'; } else { conf += ' fastcgi_pass unix:/tmp/' + host + ';\n'; } } else { conf += ' fastcgi_pass ' + upstream + ';\n'; } conf += ' include fastcgi_params;\n'; conf += ' # fastcgi_intercept_errors on; # disable asp.net error handlers\n'; conf += ' fastcgi_param PATH_INFO $fastcgi_path_info;\n'; conf += ' fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n'; conf += ' }\n'; } else { conf += ' # ASP.NET to Apache\n'; conf += ' location / {\n'; // ~ \.(aspx|asmx|ashx|axd|asax|ascx|cshtml|vbhtml|soap|rem|axd|cs|vb|config|dll)$ conf += ' proxy_set_header X-Real-IP $remote_addr;\n'; conf += ' proxy_set_header X-Forwarded-For $remote_addr;\n'; conf += ' proxy_set_header Host $host;\n'; conf += ' proxy_pass http://127.0.0.1:8080;\n'; conf += ' }\n'; } return conf; } private MakeApacheAspNetHeaders(version: string, host: string, root: string, ioMapForAll: boolean, debug: boolean): string { var monoServer = 'mod-mono-server4'; if (version == '2.0') { monoServer = 'mod-mono-server2'; } else if (version == '1.0') { monoServer = 'mod-mono-server'; } var conf = ''; conf += ` MonoServerPath ${host} "/usr/bin/${monoServer}"` + '\n'; if (debug) { conf += ` MonoDebug ${host}` + '\n'; } if (ioMapForAll) { conf += ` MonoSetEnv ${host} MONO_IOMAP=all` + '\n'; } conf += ` MonoApplications ${host} "/:${root}"` + '\n'; return conf; } private MakeApacheAspNetLocation(host: string): string { var conf = ''; conf += ' <Location />\n'; conf += ' Options FollowSymLinks Indexes\n'; conf += ' AllowOverride All\n'; conf += ' Order Allow,Deny\n'; conf += ' Allow from all\n'; conf += ' Require all granted\n'; conf += ' DirectoryIndex index.html index.htm\n'; conf += ` MonoSetServerAlias ${host}` + '\n'; conf += ' SetHandler mono\n'; conf += ' SetOutputFilter DEFLATE\n'; conf += ' SetEnvIfNoCase Request_URI ".(?:gif|jpe?g|png|js|css|txt|map|ttf|otf|woff|woff2|eot|svg)$" no$\n'; conf += ' DirectoryIndex Default.aspx default.aspx Index.aspx index.aspx Index.cshtml index.cshtml Index.vbhtml index.vbhtml\n'; conf += ' </Location>\n'; return conf; } private MakeApacheDefaultLocation(): string { var conf = ''; conf += ' <Location />\n'; // conf += ' Options FollowSymLinks Indexes\n'; conf += ' AllowOverride All\n'; conf += ' Order Allow,Deny\n'; conf += ' Allow from all\n'; conf += ' Require all granted\n'; conf += ' DirectoryIndex index.html index.htm index.php\n'; conf += ' </Location>\n'; return conf; } private GetConf($this: SiteEditorController, level: string): string { for (var i = 0; i < $this.Site.Conf.length; i++) { if ($this.Site.Conf[i].Level.toLowerCase() == level.toLowerCase()) { return $this.Site.Conf[i].Source; } } return null; } private UpdateCanAddConf($this: SiteEditorController): void { var result = []; angular.forEach($this.LevelsList, (item) => { if ($this.Site.Levels.indexOf(item) == -1) { result.push(item); } }); $this.AvailableLevels = result; console.log('Levels', $this.Site.Levels, $this.AvailableLevels); $this.CanAddConf = ($this.AvailableLevels.length > 0); if ($this.Site.Conf.length <= 0) { $this.PrepareAddConf($this); } } //#endregion } }