Merge remote-tracking branch 'upstream/dev' into clean-startup
# Conflicts: # Oqtane.Client/Program.cs # Oqtane.Server/Startup.cs
This commit is contained in:
Binary file not shown.
Before Width: | Height: | Size: 7.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.8 KiB |
@ -3,31 +3,28 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Globalization;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Oqtane.Themes.Controls;
|
||||
using System.Linq;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class AliasController : Controller
|
||||
{
|
||||
private readonly IAliasRepository _aliases;
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public AliasController(IAliasRepository aliases, IHttpContextAccessor accessor, ISyncManager syncManager, ILogManager logger)
|
||||
public AliasController(IAliasRepository aliases, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_aliases = aliases;
|
||||
_accessor = accessor;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>
|
||||
@ -35,43 +32,25 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public IEnumerable<Alias> Get()
|
||||
{
|
||||
return _aliases.GetAliases();
|
||||
var aliases = _aliases.GetAliases();
|
||||
if (!User.IsInRole(RoleNames.Host))
|
||||
{
|
||||
aliases = aliases.Where(item => item.SiteId == _alias.SiteId && item.TenantId == _alias.TenantId);
|
||||
}
|
||||
return aliases;
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public Alias Get(int id)
|
||||
{
|
||||
return _aliases.GetAlias(id);
|
||||
}
|
||||
|
||||
// GET api/<controller>/name/xxx?sync=yyyyMMddHHmmssfff
|
||||
[HttpGet("name/{**name}")]
|
||||
public Alias Get(string name, string sync)
|
||||
{
|
||||
Alias alias = null;
|
||||
|
||||
if (_accessor.HttpContext != null)
|
||||
{
|
||||
name = (name == "~") ? "" : name;
|
||||
name = _accessor.HttpContext.Request.Host.Value + "/" + WebUtility.UrlDecode(name);
|
||||
alias = _aliases.GetAlias(name);
|
||||
}
|
||||
|
||||
// get sync events
|
||||
if (alias != null)
|
||||
{
|
||||
alias.SyncDate = DateTime.UtcNow;
|
||||
alias.SyncEvents = _syncManager.GetSyncEvents(alias.TenantId, DateTime.ParseExact(sync, "yyyyMMddHHmmssfff", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
return alias;
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public Alias Post([FromBody] Alias alias)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
@ -79,12 +58,18 @@ namespace Oqtane.Controllers
|
||||
alias = _aliases.AddAlias(alias);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Alias Added {Alias}", alias);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Alias Post Attempt {Alias}", alias);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
alias = null;
|
||||
}
|
||||
return alias;
|
||||
}
|
||||
|
||||
// PUT api/<controller>/5
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public Alias Put(int id, [FromBody] Alias alias)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
@ -92,12 +77,18 @@ namespace Oqtane.Controllers
|
||||
alias = _aliases.UpdateAlias(alias);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Alias Updated {Alias}", alias);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Alias Put Attempt {Alias}", alias);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
alias = null;
|
||||
}
|
||||
return alias;
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/5
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
_aliases.DeleteAlias(id);
|
||||
|
35
Oqtane.Server/Controllers/DatabaseController.cs
Normal file
35
Oqtane.Server/Controllers/DatabaseController.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class DatabaseController : Controller
|
||||
{
|
||||
private IOptions<List<Database>> _databaseOptions;
|
||||
private IConfigManager _config;
|
||||
|
||||
public DatabaseController(IOptions<List<Database>> databaseOptions, IConfigManager config)
|
||||
{
|
||||
_databaseOptions = databaseOptions;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet]
|
||||
public IEnumerable<Database> Get()
|
||||
{
|
||||
var databases = _databaseOptions.Value;
|
||||
var master = _config.GetSetting(SettingKeys.DatabaseSection, SettingKeys.DatabaseTypeKey, "");
|
||||
if (master != "" && databases.Exists(item => item.DBType == master))
|
||||
{
|
||||
databases.Find(item => item.DBType == master).IsDefault = true;
|
||||
}
|
||||
return databases;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,31 +16,30 @@ using System.Net;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Microsoft.AspNetCore.Routing.Constraints;
|
||||
using Oqtane.Extensions;
|
||||
|
||||
// ReSharper disable StringIndexOfIsCultureSpecific.1
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class FileController : Controller
|
||||
{
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly IFileRepository _files;
|
||||
private readonly IFolderRepository _folders;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ITenantResolver _tenants;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public FileController(IWebHostEnvironment environment, IFileRepository files, IFolderRepository folders, IUserPermissions userPermissions, ITenantResolver tenants, ILogManager logger)
|
||||
public FileController(IWebHostEnvironment environment, IFileRepository files, IFolderRepository folders, IUserPermissions userPermissions, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_environment = environment;
|
||||
_files = files;
|
||||
_folders = folders;
|
||||
_userPermissions = userPermissions;
|
||||
_tenants = tenants;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?folder=x
|
||||
@ -51,11 +50,17 @@ namespace Oqtane.Controllers
|
||||
int folderid;
|
||||
if (int.TryParse(folder, out folderid))
|
||||
{
|
||||
Folder f = _folders.GetFolder(folderid);
|
||||
if (f != null && _userPermissions.IsAuthorized(User, PermissionNames.Browse, f.Permissions))
|
||||
Folder Folder = _folders.GetFolder(folderid);
|
||||
if (Folder != null && Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Browse, Folder.Permissions))
|
||||
{
|
||||
files = _files.GetFiles(folderid).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Get Attempt {FolderId}", folder);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
files = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -70,6 +75,12 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Get Attempt {Folder}", folder);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
files = null;
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
@ -79,27 +90,18 @@ namespace Oqtane.Controllers
|
||||
[HttpGet("{siteId}/{path}")]
|
||||
public IEnumerable<Models.File> Get(int siteId, string path)
|
||||
{
|
||||
var folderPath = WebUtility.UrlDecode(path);
|
||||
Folder folder = _folders.GetFolder(siteId, folderPath);
|
||||
List<Models.File> files;
|
||||
if (folder != null)
|
||||
|
||||
Folder folder = _folders.GetFolder(siteId, WebUtility.UrlDecode(path));
|
||||
if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||
{
|
||||
files = _files.GetFiles(folder.FolderId).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Folder {folder}", folder);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
return null;
|
||||
}
|
||||
files = _files.GetFiles(folder.FolderId).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "Folder Not Found {SiteId} {Path}", siteId, path);
|
||||
HttpContext.Response.StatusCode = 404;
|
||||
return null;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Get Attempt {SiteId} {Path}", siteId, path);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
files = null;
|
||||
}
|
||||
|
||||
return files;
|
||||
@ -110,23 +112,14 @@ namespace Oqtane.Controllers
|
||||
public Models.File Get(int id)
|
||||
{
|
||||
Models.File file = _files.GetFile(id);
|
||||
if (file != null)
|
||||
if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions))
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions))
|
||||
{
|
||||
return file;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access File {File}", file);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
return null;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "File Not Found {FileId}", id);
|
||||
HttpContext.Response.StatusCode = 404;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Get Attempt {FileId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -136,19 +129,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Models.File Put(int id, [FromBody] Models.File file)
|
||||
{
|
||||
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.FolderId, PermissionNames.Edit))
|
||||
var File = _files.GetFile(file.FileId, false);
|
||||
if (ModelState.IsValid && File != null && File.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.FolderId, PermissionNames.Edit))
|
||||
{
|
||||
file.Folder = _folders.GetFolder(file.FolderId);
|
||||
Models.File _file = _files.GetFile(id, false);
|
||||
if (_file.Name != file.Name || _file.FolderId != file.FolderId)
|
||||
if (File.Name != file.Name || File.FolderId != file.FolderId)
|
||||
{
|
||||
string folderpath = _folders.GetFolderPath(file.Folder);
|
||||
if (!Directory.Exists(folderpath))
|
||||
{
|
||||
Directory.CreateDirectory(folderpath);
|
||||
}
|
||||
|
||||
System.IO.File.Move(_files.GetFilePath(_file), Path.Combine(folderpath, file.Name));
|
||||
System.IO.File.Move(_files.GetFilePath(File), Path.Combine(folderpath, file.Name));
|
||||
}
|
||||
|
||||
file.Extension = Path.GetExtension(file.Name).ToLower().Replace(".", "");
|
||||
@ -157,8 +148,8 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update File {File}", file);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Put Attempt {File}", file);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
file = null;
|
||||
}
|
||||
|
||||
@ -171,30 +162,22 @@ namespace Oqtane.Controllers
|
||||
public void Delete(int id)
|
||||
{
|
||||
Models.File file = _files.GetFile(id);
|
||||
if (file != null)
|
||||
if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.Folder.FolderId, PermissionNames.Edit))
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, EntityNames.Folder, file.Folder.FolderId, PermissionNames.Edit))
|
||||
{
|
||||
_files.DeleteFile(id);
|
||||
_files.DeleteFile(id);
|
||||
|
||||
string filepath = _files.GetFilePath(file);
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
System.IO.File.Delete(filepath);
|
||||
}
|
||||
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "File Deleted {File}", file);
|
||||
}
|
||||
else
|
||||
string filepath = _files.GetFilePath(file);
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete File {FileId}", id);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
System.IO.File.Delete(filepath);
|
||||
}
|
||||
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "File Deleted {File}", file);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "File Not Found {FileId}", id);
|
||||
HttpContext.Response.StatusCode = 404;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Delete Attempt {FileId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,55 +186,57 @@ namespace Oqtane.Controllers
|
||||
public Models.File UploadFile(string url, string folderid)
|
||||
{
|
||||
Models.File file = null;
|
||||
Folder folder = _folders.GetFolder(int.Parse(folderid));
|
||||
|
||||
if (folder == null || !_userPermissions.IsAuthorized(User, PermissionNames.Edit, folder.Permissions))
|
||||
Folder folder = null;
|
||||
int FolderId;
|
||||
if (int.TryParse(folderid, out FolderId))
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||
"User Not Authorized To Download File {Url} {FolderId}", url, folderid);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
return file;
|
||||
folder = _folders.GetFolder(FolderId);
|
||||
}
|
||||
|
||||
string folderPath = _folders.GetFolderPath(folder);
|
||||
CreateDirectory(folderPath);
|
||||
|
||||
string filename = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1);
|
||||
// check for allowable file extensions
|
||||
if (!Constants.UploadableFiles.Split(',')
|
||||
.Contains(Path.GetExtension(filename).ToLower().Replace(".", "")))
|
||||
if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Edit, folder.Permissions))
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||
"File Could Not Be Downloaded From Url Due To Its File Extension {Url}", url);
|
||||
HttpContext.Response.StatusCode = (int) HttpStatusCode.Conflict;
|
||||
return file;
|
||||
}
|
||||
string folderPath = _folders.GetFolderPath(folder);
|
||||
CreateDirectory(folderPath);
|
||||
|
||||
if (!filename.IsPathOrFileValid())
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||
$"File Could Not Be Downloaded From Url Due To Its File Name Not Allowed {url}");
|
||||
HttpContext.Response.StatusCode = (int) HttpStatusCode.Conflict;
|
||||
return file;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var client = new WebClient();
|
||||
string targetPath = Path.Combine(folderPath, filename);
|
||||
// remove file if it already exists
|
||||
if (System.IO.File.Exists(targetPath))
|
||||
string filename = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1);
|
||||
// check for allowable file extensions
|
||||
if (!Constants.UploadableFiles.Split(',').Contains(Path.GetExtension(filename).ToLower().Replace(".", "")))
|
||||
{
|
||||
System.IO.File.Delete(targetPath);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "File Could Not Be Downloaded From Url Due To Its File Extension {Url}", url);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
|
||||
return file;
|
||||
}
|
||||
|
||||
client.DownloadFile(url, targetPath);
|
||||
file = _files.AddFile(CreateFile(filename, folder.FolderId, targetPath));
|
||||
if (!filename.IsPathOrFileValid())
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, $"File Could Not Be Downloaded From Url Due To Its File Name Not Allowed {url}");
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
|
||||
return file;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var client = new WebClient();
|
||||
string targetPath = Path.Combine(folderPath, filename);
|
||||
// remove file if it already exists
|
||||
if (System.IO.File.Exists(targetPath))
|
||||
{
|
||||
System.IO.File.Delete(targetPath);
|
||||
}
|
||||
|
||||
client.DownloadFile(url, targetPath);
|
||||
file = _files.AddFile(CreateFile(filename, folder.FolderId, targetPath));
|
||||
}
|
||||
catch
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "File Could Not Be Downloaded From Url {Url}", url);
|
||||
}
|
||||
}
|
||||
catch
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||
"File Could Not Be Downloaded From Url {Url}", url);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Upload Attempt {FolderId} {Url}", folderid, url);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
|
||||
return file;
|
||||
@ -274,24 +259,25 @@ namespace Oqtane.Controllers
|
||||
|
||||
string folderPath = "";
|
||||
|
||||
if (int.TryParse(folder, out int folderId))
|
||||
int FolderId;
|
||||
if (int.TryParse(folder, out FolderId))
|
||||
{
|
||||
Folder virtualFolder = _folders.GetFolder(folderId);
|
||||
if (virtualFolder != null &&
|
||||
_userPermissions.IsAuthorized(User, PermissionNames.Edit, virtualFolder.Permissions))
|
||||
Folder Folder = _folders.GetFolder(FolderId);
|
||||
if (Folder != null && Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Edit, Folder.Permissions))
|
||||
{
|
||||
folderPath = _folders.GetFolderPath(virtualFolder);
|
||||
folderPath = _folders.GetFolderPath(Folder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FolderId = -1;
|
||||
if (User.IsInRole(RoleNames.Host))
|
||||
{
|
||||
folderPath = GetFolderPath(folder);
|
||||
}
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(folderPath))
|
||||
if (!string.IsNullOrEmpty(folderPath))
|
||||
{
|
||||
CreateDirectory(folderPath);
|
||||
using (var stream = new FileStream(Path.Combine(folderPath, file.FileName), FileMode.Create))
|
||||
@ -300,16 +286,15 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
|
||||
string upload = await MergeFile(folderPath, file.FileName);
|
||||
if (upload != "" && folderId != -1)
|
||||
if (upload != "" && FolderId != -1)
|
||||
{
|
||||
_files.AddFile(CreateFile(upload, folderId, Path.Combine(folderPath, upload)));
|
||||
_files.AddFile(CreateFile(upload, FolderId, Path.Combine(folderPath, upload)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create,
|
||||
"User Not Authorized To Upload File {Folder} {File}", folder, file);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Upload Attempt {Folder} {File}", folder, file);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,32 +453,26 @@ namespace Oqtane.Controllers
|
||||
private IActionResult Download(int id, bool asAttachment)
|
||||
{
|
||||
var file = _files.GetFile(id);
|
||||
if (file != null)
|
||||
if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions))
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions))
|
||||
var filepath = _files.GetFilePath(file);
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
var filepath = _files.GetFilePath(file);
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
var result = asAttachment
|
||||
? PhysicalFile(filepath, file.GetMimeType(), file.Name)
|
||||
: PhysicalFile(filepath, file.GetMimeType());
|
||||
return result;
|
||||
}
|
||||
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "File Does Not Exist {FileId} {FilePath}", id, filepath);
|
||||
HttpContext.Response.StatusCode = 404;
|
||||
var result = asAttachment
|
||||
? PhysicalFile(filepath, file.GetMimeType(), file.Name)
|
||||
: PhysicalFile(filepath, file.GetMimeType());
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access File {FileId}", id);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "File Does Not Exist {FileId} {FilePath}", id, filepath);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "File Not Found {FileId}", id);
|
||||
HttpContext.Response.StatusCode = 404;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Access Attempt {FileId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
|
||||
string errorPath = Path.Combine(GetFolderPath("images"), "error.png");
|
||||
@ -502,7 +481,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
private string GetFolderPath(string folder)
|
||||
{
|
||||
return Utilities.PathCombine(_environment.WebRootPath, folder);
|
||||
return Utilities.PathCombine(_environment.ContentRootPath, folder);
|
||||
}
|
||||
|
||||
private void CreateDirectory(string folderpath)
|
||||
|
@ -15,22 +15,22 @@ using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class FolderController : Controller
|
||||
{
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly IFolderRepository _folders;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ITenantResolver _tenants;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public FolderController(IWebHostEnvironment environment, IFolderRepository folders, IUserPermissions userPermissions, ITenantResolver tenants, ILogManager logger)
|
||||
public FolderController(IWebHostEnvironment environment, IFolderRepository folders, IUserPermissions userPermissions, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_environment = environment;
|
||||
_folders = folders;
|
||||
_userPermissions = userPermissions;
|
||||
_tenants = tenants;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
@ -38,13 +38,23 @@ namespace Oqtane.Controllers
|
||||
public IEnumerable<Folder> Get(string siteid)
|
||||
{
|
||||
List<Folder> folders = new List<Folder>();
|
||||
foreach (Folder folder in _folders.GetFolders(int.Parse(siteid)))
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||
foreach (Folder folder in _folders.GetFolders(SiteId))
|
||||
{
|
||||
folders.Add(folder);
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||
{
|
||||
folders.Add(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
folders = null;
|
||||
}
|
||||
return folders;
|
||||
}
|
||||
|
||||
@ -53,14 +63,14 @@ namespace Oqtane.Controllers
|
||||
public Folder Get(int id)
|
||||
{
|
||||
Folder folder = _folders.GetFolder(id);
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||
if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||
{
|
||||
return folder;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Folder {Folder}", folder);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Get Attempt {FolderId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -74,23 +84,14 @@ namespace Oqtane.Controllers
|
||||
folderPath = Utilities.PathCombine(folderPath, System.IO.Path.DirectorySeparatorChar.ToString());
|
||||
}
|
||||
Folder folder = _folders.GetFolder(siteId, folderPath);
|
||||
if (folder != null)
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||
{
|
||||
return folder;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Folder {Folder}",
|
||||
folder);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
return null;
|
||||
}
|
||||
if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||
{
|
||||
return folder;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "Folder not found {path}",
|
||||
path);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Get Attempt {Path} For Site {SiteId}", path, siteId);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -100,7 +101,7 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Folder Post([FromBody] Folder folder)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && folder.SiteId == _alias.SiteId)
|
||||
{
|
||||
string permissions;
|
||||
if (folder.ParentId != null)
|
||||
@ -129,17 +130,23 @@ namespace Oqtane.Controllers
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Name Not Valid {Folder}", folder);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
folder = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Folder {Folder}", folder);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Post Attempt {Folder}", folder);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
folder = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Post Attempt {Folder}", folder);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
folder = null;
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
|
||||
@ -148,7 +155,7 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Folder Put(int id, [FromBody] Folder folder)
|
||||
{
|
||||
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, folder.FolderId, PermissionNames.Edit))
|
||||
if (ModelState.IsValid && folder.SiteId == _alias.SiteId && _folders.GetFolder(folder.FolderId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Folder, folder.FolderId, PermissionNames.Edit))
|
||||
{
|
||||
if (folder.IsPathValid())
|
||||
{
|
||||
@ -171,14 +178,14 @@ namespace Oqtane.Controllers
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Name Not Valid {Folder}", folder);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
folder = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Folder {Folder}", folder);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Put Attempt {Folder}", folder);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
folder = null;
|
||||
}
|
||||
return folder;
|
||||
@ -189,7 +196,7 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public void Put(int siteid, int folderid, int? parentid)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, EntityNames.Folder, folderid, PermissionNames.Edit))
|
||||
if (siteid == _alias.SiteId && _folders.GetFolder(folderid, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Folder, folderid, PermissionNames.Edit))
|
||||
{
|
||||
int order = 1;
|
||||
List<Folder> folders = _folders.GetFolders(siteid).ToList();
|
||||
@ -206,8 +213,8 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Folder Order {SiteId} {FolderId} {ParentId}", siteid, folderid, parentid);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "Unauthorized Folder Put Attempt {SiteId} {FolderId} {ParentId}", siteid, folderid, parentid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,26 +223,26 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, EntityNames.Folder, id, PermissionNames.Edit))
|
||||
var folder = _folders.GetFolder(id, false);
|
||||
if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Folder, id, PermissionNames.Edit))
|
||||
{
|
||||
Models.Folder _folder = _folders.GetFolder(id, false);
|
||||
if (Directory.Exists(GetFolderPath(_folder)))
|
||||
if (Directory.Exists(GetFolderPath(folder)))
|
||||
{
|
||||
Directory.Delete(GetFolderPath(_folder));
|
||||
Directory.Delete(GetFolderPath(folder));
|
||||
}
|
||||
_folders.DeleteFolder(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Folder Deleted {FolderId}", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete Folder {FolderId}", id);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Delete Attempt {FolderId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetFolderPath(Folder folder)
|
||||
{
|
||||
return Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", _tenants.GetTenant().TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path);
|
||||
return Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", _alias.TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,13 @@ using Oqtane.Modules;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Themes;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Oqtane.Repository;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class InstallationController : Controller
|
||||
{
|
||||
private readonly IConfigurationRoot _config;
|
||||
@ -24,14 +26,18 @@ namespace Oqtane.Controllers
|
||||
private readonly IDatabaseManager _databaseManager;
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
private readonly IAliasRepository _aliases;
|
||||
|
||||
public InstallationController(IConfigurationRoot config, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache)
|
||||
public InstallationController(IConfigurationRoot config, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases)
|
||||
{
|
||||
_config = config;
|
||||
_installationManager = installationManager;
|
||||
_databaseManager = databaseManager;
|
||||
_localizationManager = localizationManager;
|
||||
_cache = cache;
|
||||
_accessor = accessor;
|
||||
_aliases = aliases;
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
@ -52,11 +58,17 @@ namespace Oqtane.Controllers
|
||||
return installation;
|
||||
}
|
||||
|
||||
// GET api/<controller>/installed
|
||||
// GET api/<controller>/installed/?path=xxx
|
||||
[HttpGet("installed")]
|
||||
public Installation IsInstalled()
|
||||
public Installation IsInstalled(string path)
|
||||
{
|
||||
return _databaseManager.IsInstalled();
|
||||
var installation = _databaseManager.IsInstalled();
|
||||
if (installation.Success)
|
||||
{
|
||||
path = _accessor.HttpContext.Request.Host.Value + "/" + WebUtility.UrlDecode(path);
|
||||
installation.Alias = _aliases.GetAlias(path);
|
||||
}
|
||||
return installation;
|
||||
}
|
||||
|
||||
[HttpGet("upgrade")]
|
||||
@ -82,11 +94,11 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
if (_config.GetSection("Runtime").Value == "WebAssembly")
|
||||
{
|
||||
return File(GetAssemblies(), System.Net.Mime.MediaTypeNames.Application.Octet, "oqtane.zip");
|
||||
return File(GetAssemblies(), System.Net.Mime.MediaTypeNames.Application.Octet, "oqtane.dll");
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Models;
|
||||
@ -12,7 +12,7 @@ using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class JobController : Controller
|
||||
{
|
||||
private readonly IJobRepository _jobs;
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Enums;
|
||||
@ -9,7 +9,7 @@ using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class JobLogController : Controller
|
||||
{
|
||||
private readonly IJobLogRepository _jobLogs;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Oqtane.Enums;
|
||||
@ -9,33 +10,67 @@ using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class LanguageController : Controller
|
||||
{
|
||||
private readonly ILanguageRepository _languages;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public LanguageController(ILanguageRepository language, ILogManager logger)
|
||||
public LanguageController(ILanguageRepository language, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_languages = language;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IEnumerable<Language> Get(string siteid) => _languages.GetLanguages(int.Parse(siteid));
|
||||
public IEnumerable<Language> Get(string siteid)
|
||||
{
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return _languages.GetLanguages(SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Language Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public Language Get(int id) => _languages.GetLanguage(id);
|
||||
public Language Get(int id)
|
||||
{
|
||||
var language = _languages.GetLanguage(id);
|
||||
if (language != null && language.SiteId == _alias.SiteId)
|
||||
{
|
||||
return language;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Language Get Attempt {LanguageId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Language Post([FromBody] Language language)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && language.SiteId == _alias.SiteId)
|
||||
{
|
||||
language = _languages.AddLanguage(language);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Language Added {Language}", language);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Language Post Attempt {Language}", language);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
language = null;
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
@ -43,8 +78,18 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
_languages.DeleteLanguage(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Language Deleted {LanguageId}", id);
|
||||
var language = _languages.GetLanguage(id);
|
||||
if (language != null && language.SiteId == _alias.SiteId)
|
||||
{
|
||||
_languages.DeleteLanguage(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Language Deleted {LanguageId}", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Language Delete Attempt {LanguageId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class LocalizationController : Controller
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
|
@ -1,24 +1,28 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Enums;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class LogController : Controller
|
||||
{
|
||||
private readonly ILogManager _logger;
|
||||
private readonly ILogRepository _logs;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public LogController(ILogManager logger, ILogRepository logs)
|
||||
public LogController(ILogManager logger, ILogRepository logs, ITenantManager tenantManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_logs = logs;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x&level=y&function=z&rows=50
|
||||
@ -26,7 +30,18 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public IEnumerable<Log> Get(string siteid, string level, string function, string rows)
|
||||
{
|
||||
return _logs.GetLogs(int.Parse(siteid), level, function, int.Parse(rows));
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return _logs.GetLogs(SiteId, level, function, int.Parse(rows));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
@ -34,17 +49,32 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Log Get(int id)
|
||||
{
|
||||
return _logs.GetLog(id);
|
||||
var log = _logs.GetLog(id);
|
||||
if (log != null && log.SiteId == _alias.SiteId)
|
||||
{
|
||||
return log;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Get Attempt {LogId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
public void Post([FromBody] Log log)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && log.SiteId == _alias.SiteId)
|
||||
{
|
||||
_logger.Log(log);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Post Attempt {Log}", log);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,10 +8,11 @@ using Oqtane.Enums;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Security;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class ModuleController : Controller
|
||||
{
|
||||
private readonly IModuleRepository _modules;
|
||||
@ -20,11 +21,11 @@ namespace Oqtane.Controllers
|
||||
private readonly IModuleDefinitionRepository _moduleDefinitions;
|
||||
private readonly ISettingRepository _settings;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ITenantResolver _tenants;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public ModuleController(IModuleRepository modules, IPageModuleRepository pageModules, IPageRepository pages, IModuleDefinitionRepository moduleDefinitions, ISettingRepository settings, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger)
|
||||
public ModuleController(IModuleRepository modules, IPageModuleRepository pageModules, IPageRepository pages, IModuleDefinitionRepository moduleDefinitions, ISettingRepository settings, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_modules = modules;
|
||||
_pageModules = pageModules;
|
||||
@ -32,49 +33,61 @@ namespace Oqtane.Controllers
|
||||
_moduleDefinitions = moduleDefinitions;
|
||||
_settings = settings;
|
||||
_userPermissions = userPermissions;
|
||||
_tenants = tenants;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
[HttpGet]
|
||||
public IEnumerable<Module> Get(string siteid)
|
||||
{
|
||||
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(int.Parse(siteid)).ToList();
|
||||
List<Setting> settings = _settings.GetSettings(EntityNames.Module).ToList();
|
||||
|
||||
List<Module> modules = new List<Module>();
|
||||
foreach (PageModule pagemodule in _pageModules.GetPageModules(int.Parse(siteid)))
|
||||
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.View, pagemodule.Module.Permissions))
|
||||
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(SiteId).ToList();
|
||||
List<Setting> settings = _settings.GetSettings(EntityNames.Module).ToList();
|
||||
|
||||
foreach (PageModule pagemodule in _pageModules.GetPageModules(SiteId))
|
||||
{
|
||||
Module module = new Module();
|
||||
module.SiteId = pagemodule.Module.SiteId;
|
||||
module.ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName;
|
||||
module.AllPages = pagemodule.Module.AllPages;
|
||||
module.Permissions = pagemodule.Module.Permissions;
|
||||
module.CreatedBy = pagemodule.Module.CreatedBy;
|
||||
module.CreatedOn = pagemodule.Module.CreatedOn;
|
||||
module.ModifiedBy = pagemodule.Module.ModifiedBy;
|
||||
module.ModifiedOn = pagemodule.Module.ModifiedOn;
|
||||
module.IsDeleted = pagemodule.IsDeleted;
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.View, pagemodule.Module.Permissions))
|
||||
{
|
||||
Module module = new Module();
|
||||
module.SiteId = pagemodule.Module.SiteId;
|
||||
module.ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName;
|
||||
module.AllPages = pagemodule.Module.AllPages;
|
||||
module.Permissions = pagemodule.Module.Permissions;
|
||||
module.CreatedBy = pagemodule.Module.CreatedBy;
|
||||
module.CreatedOn = pagemodule.Module.CreatedOn;
|
||||
module.ModifiedBy = pagemodule.Module.ModifiedBy;
|
||||
module.ModifiedOn = pagemodule.Module.ModifiedOn;
|
||||
module.IsDeleted = pagemodule.IsDeleted;
|
||||
|
||||
module.PageModuleId = pagemodule.PageModuleId;
|
||||
module.ModuleId = pagemodule.ModuleId;
|
||||
module.PageId = pagemodule.PageId;
|
||||
module.Title = pagemodule.Title;
|
||||
module.Pane = pagemodule.Pane;
|
||||
module.Order = pagemodule.Order;
|
||||
module.ContainerType = pagemodule.ContainerType;
|
||||
module.PageModuleId = pagemodule.PageModuleId;
|
||||
module.ModuleId = pagemodule.ModuleId;
|
||||
module.PageId = pagemodule.PageId;
|
||||
module.Title = pagemodule.Title;
|
||||
module.Pane = pagemodule.Pane;
|
||||
module.Order = pagemodule.Order;
|
||||
module.ContainerType = pagemodule.ContainerType;
|
||||
|
||||
module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);
|
||||
module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);
|
||||
module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
|
||||
modules.Add(module);
|
||||
modules.Add(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
modules = null;
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
@ -83,19 +96,18 @@ namespace Oqtane.Controllers
|
||||
public Module Get(int id)
|
||||
{
|
||||
Module module = _modules.GetModule(id);
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.View, module.Permissions))
|
||||
if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User,PermissionNames.View, module.Permissions))
|
||||
{
|
||||
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(module.SiteId).ToList();
|
||||
module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);
|
||||
module.Settings = _settings.GetSettings(EntityNames.Module, id)
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
|
||||
return module;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Module {Module}", module);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Get Attempt {ModuleId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -105,16 +117,16 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Module Post([FromBody] Module module)
|
||||
{
|
||||
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, module.PageId, PermissionNames.Edit))
|
||||
if (ModelState.IsValid && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, module.PageId, PermissionNames.Edit))
|
||||
{
|
||||
module = _modules.AddModule(module);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Added {Module}", module);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Module {Module}", module);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Post Attempt {Module}", module);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
module = null;
|
||||
}
|
||||
return module;
|
||||
@ -125,7 +137,7 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Module Put(int id, [FromBody] Module module)
|
||||
{
|
||||
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit))
|
||||
if (ModelState.IsValid && module.SiteId == _alias.SiteId && _modules.GetModule(module.ModuleId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit))
|
||||
{
|
||||
module = _modules.UpdateModule(module);
|
||||
if (module.AllPages)
|
||||
@ -142,12 +154,12 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
}
|
||||
}
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Module {Module}", module);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Put Attempt {Module}", module);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
module = null;
|
||||
}
|
||||
return module;
|
||||
@ -158,16 +170,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, EntityNames.Module, id, PermissionNames.Edit))
|
||||
var module = _modules.GetModule(id);
|
||||
if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, module.ModuleId, PermissionNames.Edit))
|
||||
{
|
||||
_modules.DeleteModule(id);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Deleted {ModuleId}", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete Module {ModuleId}", id);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Delete Attempt {ModuleId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,14 +190,15 @@ namespace Oqtane.Controllers
|
||||
public string Export(int moduleid)
|
||||
{
|
||||
string content = "";
|
||||
if (_userPermissions.IsAuthorized(User, EntityNames.Module, moduleid, PermissionNames.Edit))
|
||||
var module = _modules.GetModule(moduleid);
|
||||
if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit))
|
||||
{
|
||||
content = _modules.ExportModule(moduleid);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Other, "User Not Authorized To Export Module {ModuleId}", moduleid);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Export Attempt {ModuleId}", moduleid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
@ -195,14 +209,15 @@ namespace Oqtane.Controllers
|
||||
public bool Import(int moduleid, [FromBody] string content)
|
||||
{
|
||||
bool success = false;
|
||||
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Module, moduleid, PermissionNames.Edit))
|
||||
var module = _modules.GetModule(moduleid);
|
||||
if (ModelState.IsValid && module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit))
|
||||
{
|
||||
success = _modules.ImportModule(moduleid, content);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Other, "User Not Authorized To Import Module {ModuleId}", moduleid);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Import Attempt {ModuleId}", moduleid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
@ -1,21 +1,52 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Oqtane.Infrastructure;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
public class ModuleControllerBase : Controller
|
||||
{
|
||||
protected readonly ILogManager _logger;
|
||||
protected int _entityId = -1; // passed as a querystring parameter for policy authorization and used for validation
|
||||
|
||||
// parameters for policy authorization and validation
|
||||
protected Dictionary<string, int> _authEntityId = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
protected int _entityId = -1; // legacy support
|
||||
|
||||
public ModuleControllerBase(ILogManager logger, IHttpContextAccessor accessor)
|
||||
{
|
||||
_logger = logger;
|
||||
if (accessor.HttpContext.Request.Query.ContainsKey("entityid"))
|
||||
|
||||
// populate policy authorization dictionary from querystring
|
||||
int value;
|
||||
foreach (var param in accessor.HttpContext.Request.Query)
|
||||
{
|
||||
if (param.Key.StartsWith("auth") && param.Key.EndsWith("id") && int.TryParse(param.Value, out value))
|
||||
{
|
||||
_authEntityId.Add(param.Key.Substring(4, param.Key.Length - 6), value);
|
||||
}
|
||||
}
|
||||
|
||||
// legacy support
|
||||
if (_authEntityId.Count == 0 && accessor.HttpContext.Request.Query.ContainsKey("entityid"))
|
||||
{
|
||||
_entityId = int.Parse(accessor.HttpContext.Request.Query["entityid"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected int AuthEntityId(string entityname)
|
||||
{
|
||||
if (_authEntityId.ContainsKey(entityname))
|
||||
{
|
||||
return _authEntityId[entityname];
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,11 @@ using Oqtane.Security;
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Text.Json;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class ModuleDefinitionController : Controller
|
||||
{
|
||||
private readonly IModuleDefinitionRepository _moduleDefinitions;
|
||||
@ -27,9 +28,11 @@ namespace Oqtane.Controllers
|
||||
private readonly IInstallationManager _installationManager;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ITenantManager _tenantManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, ITenantRepository tenants, ISqlRepository sql, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ILogManager logger)
|
||||
public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, ITenantRepository tenants, ISqlRepository sql, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ITenantManager tenantManager, ILogManager logger)
|
||||
{
|
||||
_moduleDefinitions = moduleDefinitions;
|
||||
_tenants = tenants;
|
||||
@ -38,59 +41,115 @@ namespace Oqtane.Controllers
|
||||
_installationManager = installationManager;
|
||||
_environment = environment;
|
||||
_serviceProvider = serviceProvider;
|
||||
_tenantManager = tenantManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
[HttpGet]
|
||||
public IEnumerable<ModuleDefinition> Get(string siteid)
|
||||
{
|
||||
List<ModuleDefinition> moduledefinitions = new List<ModuleDefinition>();
|
||||
foreach(ModuleDefinition moduledefinition in _moduleDefinitions.GetModuleDefinitions(int.Parse(siteid)))
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.Utilize, moduledefinition.Permissions))
|
||||
List<ModuleDefinition> moduledefinitions = new List<ModuleDefinition>();
|
||||
foreach (ModuleDefinition moduledefinition in _moduleDefinitions.GetModuleDefinitions(SiteId))
|
||||
{
|
||||
moduledefinitions.Add(moduledefinition);
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Utilize, moduledefinition.Permissions))
|
||||
{
|
||||
moduledefinitions.Add(moduledefinition);
|
||||
}
|
||||
}
|
||||
return moduledefinitions;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
return moduledefinitions;
|
||||
}
|
||||
|
||||
// GET api/<controller>/5?siteid=x
|
||||
[HttpGet("{id}")]
|
||||
public ModuleDefinition Get(int id, string siteid)
|
||||
{
|
||||
ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, int.Parse(siteid));
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.Utilize, moduledefinition.Permissions))
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return moduledefinition;
|
||||
ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, SiteId);
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Utilize, moduledefinition.Permissions))
|
||||
{
|
||||
return moduledefinition;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Get Attempt {ModuleDefinitionId} {SiteId}", id, siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access ModuleDefinition {ModuleDefinition}", moduledefinition);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Get Attempt {ModuleDefinitionId} {SiteId}", id, siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition)
|
||||
{
|
||||
if (ModelState.IsValid && moduleDefinition.SiteId == _alias.SiteId)
|
||||
{
|
||||
string rootPath;
|
||||
DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath);
|
||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", moduleDefinition.Template, Path.DirectorySeparatorChar.ToString());
|
||||
|
||||
if (moduleDefinition.Template.ToLower().Contains("internal"))
|
||||
{
|
||||
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", Oqtane.Client";
|
||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, moduleDefinition.Owner + "." + moduleDefinition.Name, Path.DirectorySeparatorChar.ToString());
|
||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane";
|
||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane";
|
||||
}
|
||||
|
||||
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Definition Created {ModuleDefinition}", moduleDefinition);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Post Attempt {ModuleDefinition}", moduleDefinition);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
moduleDefinition = null;
|
||||
}
|
||||
|
||||
return moduleDefinition;
|
||||
}
|
||||
|
||||
// PUT api/<controller>/5
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Put(int id, [FromBody] ModuleDefinition moduleDefinition)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && moduleDefinition.SiteId == _alias.SiteId && _moduleDefinitions.GetModuleDefinition(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId) != null)
|
||||
{
|
||||
_moduleDefinitions.UpdateModuleDefinition(moduleDefinition);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Module Definition Updated {ModuleDefinition}", moduleDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("install")]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public void InstallModules()
|
||||
{
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Modules Installed");
|
||||
_installationManager.InstallPackages("Modules");
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Put Attempt {ModuleDefinition}", moduleDefinition);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/5?siteid=x
|
||||
@ -99,7 +158,7 @@ namespace Oqtane.Controllers
|
||||
public void Delete(int id, int siteid)
|
||||
{
|
||||
ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, siteid);
|
||||
if (moduledefinition != null && Utilities.GetAssemblyName(moduledefinition.ServerManagerType) != "Oqtane.Server")
|
||||
if (moduledefinition != null && moduledefinition.SiteId == _alias.SiteId && Utilities.GetAssemblyName(moduledefinition.ServerManagerType) != "Oqtane.Server")
|
||||
{
|
||||
// execute uninstall logic or scripts
|
||||
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType))
|
||||
@ -111,6 +170,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
if (moduletype.GetInterface("IInstallable") != null)
|
||||
{
|
||||
_tenantManager.SetTenant(tenant.TenantId);
|
||||
var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
|
||||
((IInstallable)moduleobject).Uninstall(tenant);
|
||||
}
|
||||
@ -128,25 +188,8 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
|
||||
// remove module assets
|
||||
string assetpath = Path.Combine(_environment.WebRootPath, "Modules", Utilities.GetTypeName(moduledefinition.ModuleDefinitionName));
|
||||
if (System.IO.File.Exists(Path.Combine(assetpath, "assets.json")))
|
||||
if (_installationManager.UninstallPackage(moduledefinition.PackageName))
|
||||
{
|
||||
// use assets.json to clean up file resources
|
||||
List<string> assets = JsonSerializer.Deserialize<List<string>>(System.IO.File.ReadAllText(Path.Combine(assetpath, "assets.json")));
|
||||
assets.Reverse();
|
||||
foreach(string asset in assets)
|
||||
{
|
||||
// legacy support for assets that were stored as absolute paths
|
||||
string filepath = asset.StartsWith("\\") ? Path.Combine(_environment.ContentRootPath, asset.Substring(1)) : asset;
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
System.IO.File.Delete(filepath);
|
||||
if (!Directory.EnumerateFiles(Path.GetDirectoryName(filepath)).Any())
|
||||
{
|
||||
Directory.Delete(Path.GetDirectoryName(filepath));
|
||||
}
|
||||
}
|
||||
}
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assets Removed For {ModuleDefinitionName}", moduledefinition.ModuleDefinitionName);
|
||||
}
|
||||
else
|
||||
@ -160,6 +203,7 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
|
||||
// clean up module static resource folder
|
||||
string assetpath = Path.Combine(_environment.WebRootPath, "Modules", Utilities.GetTypeName(moduledefinition.ModuleDefinitionName));
|
||||
if (Directory.Exists(assetpath))
|
||||
{
|
||||
Directory.Delete(assetpath, true);
|
||||
@ -170,44 +214,51 @@ namespace Oqtane.Controllers
|
||||
_moduleDefinitions.DeleteModuleDefinition(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Delete Attempt {ModuleDefinitionId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("install")]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public void InstallModules()
|
||||
{
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Modules Installed");
|
||||
_installationManager.InstallPackages();
|
||||
}
|
||||
|
||||
// GET: api/<controller>/templates
|
||||
[HttpGet("templates")]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public List<string> GetTemplates()
|
||||
public List<Template> GetTemplates()
|
||||
{
|
||||
var templates = new List<string>();
|
||||
var templates = new List<Template>();
|
||||
var root = Directory.GetParent(_environment.ContentRootPath);
|
||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", Path.DirectorySeparatorChar.ToString());
|
||||
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||
{
|
||||
templates.Add(directory.Replace(templatePath, ""));
|
||||
string name = directory.Replace(templatePath, "");
|
||||
if (System.IO.File.Exists(Path.Combine(directory, "template.json")))
|
||||
{
|
||||
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(Path.Combine(directory, "template.json")));
|
||||
template.Name = name;
|
||||
template.Location = "";
|
||||
if (template.Type.ToLower() != "internal")
|
||||
{
|
||||
template.Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString());
|
||||
}
|
||||
templates.Add(template);
|
||||
}
|
||||
else
|
||||
{
|
||||
templates.Add(new Template { Name = name, Title = name, Type = "External", Version = "", Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString()) });
|
||||
}
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
string rootPath;
|
||||
DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath);
|
||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", moduleDefinition.Template,Path.DirectorySeparatorChar.ToString());
|
||||
|
||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName , moduleDefinition.Owner + "." + moduleDefinition.Name,Path.DirectorySeparatorChar.ToString());
|
||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane";
|
||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane";
|
||||
|
||||
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Definition Created {ModuleDefinition}", moduleDefinition);
|
||||
}
|
||||
|
||||
return moduleDefinition;
|
||||
}
|
||||
|
||||
private void ProcessTemplatesRecursively(DirectoryInfo current, string rootPath, string rootFolder, string templatePath, ModuleDefinition moduleDefinition)
|
||||
{
|
||||
// process folder
|
||||
|
@ -7,21 +7,24 @@ using Oqtane.Shared;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Security;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class NotificationController : Controller
|
||||
{
|
||||
private readonly INotificationRepository _notifications;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public NotificationController(INotificationRepository notifications, IUserPermissions userPermissions, ILogManager logger)
|
||||
public NotificationController(INotificationRepository notifications, IUserPermissions userPermissions, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_notifications = notifications;
|
||||
_userPermissions = userPermissions;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x&type=y&userid=z
|
||||
@ -30,17 +33,27 @@ namespace Oqtane.Controllers
|
||||
public IEnumerable<Notification> Get(string siteid, string direction, string userid)
|
||||
{
|
||||
IEnumerable<Notification> notifications = null;
|
||||
if (IsAuthorized(int.Parse(userid)))
|
||||
|
||||
int SiteId;
|
||||
int UserId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId && int.TryParse(userid, out UserId) && IsAuthorized(UserId))
|
||||
{
|
||||
if (direction == "to")
|
||||
{
|
||||
notifications = _notifications.GetNotifications(int.Parse(siteid), -1, int.Parse(userid));
|
||||
notifications = _notifications.GetNotifications(SiteId, -1, UserId);
|
||||
}
|
||||
else
|
||||
{
|
||||
notifications = _notifications.GetNotifications(int.Parse(siteid), int.Parse(userid), -1);
|
||||
notifications = _notifications.GetNotifications(SiteId, UserId, -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Get Attempt {SiteId} {Direction} {UserId}", siteid, direction, userid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
notifications = null;
|
||||
}
|
||||
|
||||
return notifications;
|
||||
}
|
||||
|
||||
@ -50,11 +63,16 @@ namespace Oqtane.Controllers
|
||||
public Notification Get(int id)
|
||||
{
|
||||
Notification notification = _notifications.GetNotification(id);
|
||||
if (!(IsAuthorized(notification.FromUserId) || IsAuthorized(notification.ToUserId)))
|
||||
if (notification != null && notification.SiteId == _alias.SiteId && (IsAuthorized(notification.FromUserId) || IsAuthorized(notification.ToUserId)))
|
||||
{
|
||||
notification = null;
|
||||
return notification;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Get Attempt {NotificationId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
return notification;
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
@ -62,11 +80,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Notification Post([FromBody] Notification notification)
|
||||
{
|
||||
if (IsAuthorized(notification.FromUserId))
|
||||
if (ModelState.IsValid && notification.SiteId == _alias.SiteId && IsAuthorized(notification.FromUserId))
|
||||
{
|
||||
notification = _notifications.AddNotification(notification);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {NotificationId}", notification.NotificationId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Post Attempt {Notification}", notification);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
notification = null;
|
||||
}
|
||||
return notification;
|
||||
}
|
||||
|
||||
@ -75,11 +99,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Notification Put(int id, [FromBody] Notification notification)
|
||||
{
|
||||
if (IsAuthorized(notification.FromUserId))
|
||||
if (ModelState.IsValid && notification.SiteId == _alias.SiteId && _notifications.GetNotification(notification.NotificationId, false) != null && IsAuthorized(notification.FromUserId))
|
||||
{
|
||||
notification = _notifications.UpdateNotification(notification);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {NotificationId}", notification.NotificationId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Put Attempt {Notification}", notification);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
notification = null;
|
||||
}
|
||||
return notification;
|
||||
}
|
||||
|
||||
@ -89,11 +119,16 @@ namespace Oqtane.Controllers
|
||||
public void Delete(int id)
|
||||
{
|
||||
Notification notification = _notifications.GetNotification(id);
|
||||
if (IsAuthorized(notification.FromUserId) || IsAuthorized(notification.ToUserId))
|
||||
if (notification != null && notification.SiteId == _alias.SiteId && (IsAuthorized(notification.FromUserId) || IsAuthorized(notification.ToUserId)))
|
||||
{
|
||||
_notifications.DeleteNotification(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Notification Deleted {NotificationId}", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Delete Attempt {NotificationId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsAuthorized(int? userid)
|
||||
|
@ -1,28 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Oqtane.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Enums;
|
||||
// ReSharper disable PartialTypeWithSinglePart
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class PackageController : Controller
|
||||
{
|
||||
private readonly IInstallationManager _installationManager;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly ILogManager _logger;
|
||||
|
||||
public PackageController(IWebHostEnvironment environment)
|
||||
public PackageController(IInstallationManager installationManager, IWebHostEnvironment environment, ILogManager logger)
|
||||
{
|
||||
_installationManager = installationManager;
|
||||
_environment = environment;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
// GET: api/<controller>?tag=x
|
||||
@ -60,7 +65,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
using (var httpClient = new HttpClient())
|
||||
{
|
||||
folder = Path.Combine(_environment.WebRootPath, folder);
|
||||
folder = Path.Combine(_environment.ContentRootPath, folder);
|
||||
var response = await httpClient.GetAsync("https://www.nuget.org/api/v2/package/" + packageid.ToLower() + "/" + version).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
string filename = packageid + "." + version + ".nupkg";
|
||||
@ -86,6 +91,14 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("install")]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public void InstallPackages()
|
||||
{
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Packages Installed");
|
||||
_installationManager.InstallPackages();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class SearchResult
|
||||
|
@ -13,46 +13,60 @@ using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class PageController : Controller
|
||||
{
|
||||
private readonly IPageRepository _pages;
|
||||
private readonly IModuleRepository _modules;
|
||||
private readonly IPageModuleRepository _pageModules;
|
||||
private readonly IPermissionRepository _permissionRepository;
|
||||
private readonly ISettingRepository _settings;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ITenantResolver _tenants;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, ISettingRepository settings, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger)
|
||||
public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, IPermissionRepository permissionRepository, ISettingRepository settings, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_pages = pages;
|
||||
_modules = modules;
|
||||
_pageModules = pageModules;
|
||||
_permissionRepository = permissionRepository;
|
||||
_settings = settings;
|
||||
_userPermissions = userPermissions;
|
||||
_tenants = tenants;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
[HttpGet]
|
||||
public IEnumerable<Page> Get(string siteid)
|
||||
{
|
||||
List<Setting> settings = _settings.GetSettings(EntityNames.Page).ToList();
|
||||
|
||||
List<Page> pages = new List<Page>();
|
||||
foreach (Page page in _pages.GetPages(int.Parse(siteid)))
|
||||
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions))
|
||||
List<Setting> settings = _settings.GetSettings(EntityNames.Page).ToList();
|
||||
|
||||
foreach (Page page in _pages.GetPages(SiteId))
|
||||
{
|
||||
page.Settings = settings.Where(item => item.EntityId == page.PageId)
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
pages.Add(page);
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.View, page.Permissions))
|
||||
{
|
||||
page.Settings = settings.Where(item => item.EntityId == page.PageId)
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
pages.Add(page);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
pages = null;
|
||||
}
|
||||
|
||||
return pages;
|
||||
}
|
||||
|
||||
@ -60,7 +74,7 @@ namespace Oqtane.Controllers
|
||||
[HttpGet("{id}")]
|
||||
public Page Get(int id, string userid)
|
||||
{
|
||||
Page page;
|
||||
Page page = null;
|
||||
if (string.IsNullOrEmpty(userid))
|
||||
{
|
||||
page = _pages.GetPage(id);
|
||||
@ -77,8 +91,8 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Page {Page}", page);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Page}", page);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -88,7 +102,7 @@ namespace Oqtane.Controllers
|
||||
public Page Get(string path, int siteid)
|
||||
{
|
||||
Page page = _pages.GetPage(WebUtility.UrlDecode(path), siteid);
|
||||
if (page != null)
|
||||
if (page != null && page.SiteId == _alias.SiteId)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions))
|
||||
{
|
||||
@ -98,14 +112,15 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Page {Page}", page);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Page}", page);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpContext.Response.StatusCode = 404;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Path} for Site {SiteId}", path, siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -115,7 +130,7 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Page Post([FromBody] Page page)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && page.SiteId == _alias.SiteId)
|
||||
{
|
||||
string permissions;
|
||||
if (page.ParentId != null)
|
||||
@ -132,7 +147,7 @@ namespace Oqtane.Controllers
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.Edit, permissions))
|
||||
{
|
||||
page = _pages.AddPage(page);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, page.SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Page Added {Page}", page);
|
||||
|
||||
if (!page.Path.StartsWith("admin/"))
|
||||
@ -147,11 +162,17 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Page {Page}", page);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Warning, this, LogFunction.Create, "User Not Authorized To Add Page {Page}", page);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
page = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Post Attempt {Page}", page);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
page = null;
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@ -162,7 +183,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
Page page = null;
|
||||
Page parent = _pages.GetPage(id);
|
||||
if (parent != null && parent.IsPersonalizable && _userPermissions.GetUser(User).UserId == int.Parse(userid))
|
||||
if (parent != null && parent.SiteId == _alias.SiteId && parent.IsPersonalizable && _userPermissions.GetUser(User).UserId == int.Parse(userid))
|
||||
{
|
||||
page = new Page();
|
||||
page.SiteId = parent.SiteId;
|
||||
@ -183,7 +204,7 @@ namespace Oqtane.Controllers
|
||||
page.IsPersonalizable = false;
|
||||
page.UserId = int.Parse(userid);
|
||||
page = _pages.AddPage(page);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, page.SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId);
|
||||
|
||||
// copy modules
|
||||
List<PageModule> pagemodules = _pageModules.GetPageModules(page.SiteId).ToList();
|
||||
@ -217,6 +238,12 @@ namespace Oqtane.Controllers
|
||||
_pageModules.AddPageModule(pagemodule);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Post Attempt {PageId} By User {UserId}", id, userid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
page = null;
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@ -225,27 +252,87 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Page Put(int id, [FromBody] Page page)
|
||||
{
|
||||
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit))
|
||||
if (ModelState.IsValid && page.SiteId == _alias.SiteId && _pages.GetPage(page.PageId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit))
|
||||
{
|
||||
// preserve page permissions
|
||||
var oldPermissions = _permissionRepository.GetPermissions(EntityNames.Page, page.PageId).ToList();
|
||||
|
||||
page = _pages.UpdatePage(page);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, page.SiteId);
|
||||
|
||||
// get differences between old and new page permissions
|
||||
var newPermissions = _permissionRepository.DecodePermissions(page.Permissions, page.SiteId, EntityNames.Page, page.PageId).ToList();
|
||||
var added = GetPermissionsDifferences(newPermissions, oldPermissions);
|
||||
var removed = GetPermissionsDifferences(oldPermissions, newPermissions);
|
||||
|
||||
// synchronize module permissions
|
||||
if (added.Count > 0 || removed.Count > 0)
|
||||
{
|
||||
foreach (PageModule pageModule in _pageModules.GetPageModules(page.PageId, "").ToList())
|
||||
{
|
||||
var modulePermissions = _permissionRepository.GetPermissions(EntityNames.Module, pageModule.Module.ModuleId).ToList();
|
||||
//var modulePermissions = _permissionRepository.DecodePermissions(pageModule.Module.Permissions, page.SiteId, EntityNames.Module, pageModule.ModuleId).ToList();
|
||||
// permissions added
|
||||
foreach(Permission permission in added)
|
||||
{
|
||||
if (!modulePermissions.Any(item => item.PermissionName == permission.PermissionName
|
||||
&& item.RoleId == permission.RoleId && item.UserId == permission.UserId && item.IsAuthorized == permission.IsAuthorized))
|
||||
{
|
||||
_permissionRepository.AddPermission(new Permission
|
||||
{
|
||||
SiteId = page.SiteId,
|
||||
EntityName = EntityNames.Module,
|
||||
EntityId = pageModule.ModuleId,
|
||||
PermissionName = permission.PermissionName,
|
||||
RoleId = permission.RoleId,
|
||||
UserId = permission.UserId,
|
||||
IsAuthorized = permission.IsAuthorized
|
||||
});
|
||||
}
|
||||
}
|
||||
// permissions removed
|
||||
foreach (Permission permission in removed)
|
||||
{
|
||||
var modulePermission = modulePermissions.FirstOrDefault(item => item.PermissionName == permission.PermissionName
|
||||
&& item.RoleId == permission.RoleId && item.UserId == permission.UserId && item.IsAuthorized == permission.IsAuthorized);
|
||||
if (modulePermission != null)
|
||||
{
|
||||
_permissionRepository.DeletePermission(modulePermission.PermissionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Updated {Page}", page);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Page {Page}", page);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Put Attempt {Page}", page);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
page = null;
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
private List<Permission> GetPermissionsDifferences(List<Permission> permissions1, List<Permission> permissions2)
|
||||
{
|
||||
var differences = new List<Permission>();
|
||||
foreach (Permission p in permissions1)
|
||||
{
|
||||
if (!permissions2.Any(item => item.PermissionName == p.PermissionName && item.RoleId == p.RoleId && item.UserId == p.UserId && item.IsAuthorized == p.IsAuthorized))
|
||||
{
|
||||
differences.Add(p);
|
||||
}
|
||||
}
|
||||
return differences;
|
||||
}
|
||||
|
||||
// PUT api/<controller>/?siteid=x&pageid=y&parentid=z
|
||||
[HttpPut]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public void Put(int siteid, int pageid, int? parentid)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit))
|
||||
if (siteid == _alias.SiteId && siteid == _alias.SiteId && _pages.GetPage(pageid, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit))
|
||||
{
|
||||
int order = 1;
|
||||
List<Page> pages = _pages.GetPages(siteid).ToList();
|
||||
@ -258,13 +345,13 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
order += 2;
|
||||
}
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, siteid);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, siteid);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Order Updated {SiteId} {PageId} {ParentId}", siteid, pageid, parentid);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Page Order {SiteId} {PageId} {ParentId}", siteid, pageid, parentid);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Put Attempt {SiteId} {PageId} {ParentId}", siteid, pageid, parentid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,17 +361,18 @@ namespace Oqtane.Controllers
|
||||
public void Delete(int id)
|
||||
{
|
||||
Page page = _pages.GetPage(id);
|
||||
if (_userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit))
|
||||
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit))
|
||||
{
|
||||
_pages.DeletePage(page.PageId);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, page.SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Page Deleted {PageId}", page.PageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete Page {PageId}", page.PageId);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Delete Attempt {PageId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,25 +8,28 @@ using Oqtane.Enums;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Security;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class PageModuleController : Controller
|
||||
{
|
||||
private readonly IPageModuleRepository _pageModules;
|
||||
private readonly IPageRepository _pages;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ITenantResolver _tenants;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public PageModuleController(IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger)
|
||||
public PageModuleController(IPageModuleRepository pageModules, IPageRepository pages, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_pageModules = pageModules;
|
||||
_pages = pages;
|
||||
_userPermissions = userPermissions;
|
||||
_tenants = tenants;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
@ -34,14 +37,14 @@ namespace Oqtane.Controllers
|
||||
public PageModule Get(int id)
|
||||
{
|
||||
PageModule pagemodule = _pageModules.GetPageModule(id);
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.View, pagemodule.Module.Permissions))
|
||||
if (pagemodule != null && pagemodule.Module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, pagemodule.Module.Permissions))
|
||||
{
|
||||
return pagemodule;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access PageModule {PageModule}", pagemodule);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Get Attempt {PageModuleId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -51,14 +54,14 @@ namespace Oqtane.Controllers
|
||||
public PageModule Get(int pageid, int moduleid)
|
||||
{
|
||||
PageModule pagemodule = _pageModules.GetPageModule(pageid, moduleid);
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.View, pagemodule.Module.Permissions))
|
||||
if (pagemodule != null && pagemodule.Module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User,PermissionNames.View, pagemodule.Module.Permissions))
|
||||
{
|
||||
return pagemodule;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access PageModule {PageModule}", pagemodule);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Get Attempt {PageId} {ModuleId}", pageid, moduleid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -68,16 +71,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public PageModule Post([FromBody] PageModule pageModule)
|
||||
{
|
||||
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, pageModule.PageId, PermissionNames.Edit))
|
||||
var page = _pages.GetPage(pageModule.PageId);
|
||||
if (ModelState.IsValid && page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, pageModule.PageId, PermissionNames.Edit))
|
||||
{
|
||||
pageModule = _pageModules.AddPageModule(pageModule);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Page Module Added {PageModule}", pageModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add PageModule {PageModule}", pageModule);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Post Attempt {PageModule}", pageModule);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
pageModule = null;
|
||||
}
|
||||
return pageModule;
|
||||
@ -88,16 +92,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public PageModule Put(int id, [FromBody] PageModule pageModule)
|
||||
{
|
||||
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Module, pageModule.ModuleId, PermissionNames.Edit))
|
||||
var page = _pages.GetPage(pageModule.PageId);
|
||||
if (ModelState.IsValid && page != null && page.SiteId == _alias.SiteId && _pageModules.GetPageModule(pageModule.PageModuleId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Module, pageModule.ModuleId, PermissionNames.Edit))
|
||||
{
|
||||
pageModule = _pageModules.UpdatePageModule(pageModule);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Module Updated {PageModule}", pageModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update PageModule {PageModule}", pageModule);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Put Attempt {PageModule}", pageModule);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
pageModule = null;
|
||||
}
|
||||
return pageModule;
|
||||
@ -108,7 +113,8 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public void Put(int pageid, string pane)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit))
|
||||
var page = _pages.GetPage(pageid);
|
||||
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit))
|
||||
{
|
||||
int order = 1;
|
||||
List<PageModule> pagemodules = _pageModules.GetPageModules(pageid, pane).OrderBy(item => item.Order).ToList();
|
||||
@ -121,14 +127,14 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
order += 2;
|
||||
}
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Module Order Updated {PageId} {Pane}", pageid, pane);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Page Module Order {PageId} {Pane}", pageid, pane);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
}
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Put Attempt {PageId} {Pane}", pageid, pane);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/5
|
||||
@ -137,16 +143,16 @@ namespace Oqtane.Controllers
|
||||
public void Delete(int id)
|
||||
{
|
||||
PageModule pagemodule = _pageModules.GetPageModule(id);
|
||||
if (_userPermissions.IsAuthorized(User, EntityNames.Page, pagemodule.PageId, PermissionNames.Edit))
|
||||
if (pagemodule != null && pagemodule.Module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, pagemodule.PageId, PermissionNames.Edit))
|
||||
{
|
||||
_pageModules.DeletePageModule(id);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Page Module Deleted {PageModuleId}", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete PageModule {PageModuleId}", id);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Delete Attempt {PageModuleId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Enums;
|
||||
@ -6,33 +6,56 @@ using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class ProfileController : Controller
|
||||
{
|
||||
private readonly IProfileRepository _profiles;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public ProfileController(IProfileRepository profiles, ILogManager logger)
|
||||
public ProfileController(IProfileRepository profiles, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_profiles = profiles;
|
||||
_logger = logger;
|
||||
}
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
[HttpGet]
|
||||
// GET: api/<controller>?siteid=x
|
||||
[HttpGet]
|
||||
public IEnumerable<Profile> Get(string siteid)
|
||||
{
|
||||
return _profiles.GetProfiles(int.Parse(siteid));
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return _profiles.GetProfiles(SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
public Profile Get(int id)
|
||||
{
|
||||
return _profiles.GetProfile(id);
|
||||
var profile = _profiles.GetProfile(id);
|
||||
if (profile != null && profile.SiteId == _alias.SiteId)
|
||||
{
|
||||
return profile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Get Attempt {ProfileId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
@ -40,11 +63,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Profile Post([FromBody] Profile profile)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && profile.SiteId == _alias.SiteId)
|
||||
{
|
||||
profile = _profiles.AddProfile(profile);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Profile Added {Profile}", profile);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Post Attempt {Profile}", profile);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
profile = null;
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
@ -53,11 +82,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Profile Put(int id, [FromBody] Profile profile)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && profile.SiteId == _alias.SiteId && _profiles.GetProfile(profile.ProfileId, false) != null)
|
||||
{
|
||||
profile = _profiles.UpdateProfile(profile);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Profile Updated {Profile}", profile);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Put Attempt {Profile}", profile);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
profile = null;
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
@ -66,8 +101,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
_profiles.DeleteProfile(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Profile Deleted {ProfileId}", id);
|
||||
var profile = _profiles.GetProfile(id);
|
||||
if (profile != null && profile.SiteId == _alias.SiteId)
|
||||
{
|
||||
_profiles.DeleteProfile(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Profile Deleted {ProfileId}", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Delete Attempt {ProfileId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Enums;
|
||||
@ -6,35 +6,62 @@ using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class RoleController : Controller
|
||||
{
|
||||
private readonly IRoleRepository _roles;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public RoleController(IRoleRepository roles, ILogManager logger)
|
||||
public RoleController(IRoleRepository roles, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_roles = roles;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
// GET: api/<controller>?siteid=x&global=true/false
|
||||
[HttpGet]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public IEnumerable<Role> Get(string siteid)
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public IEnumerable<Role> Get(string siteid, string global)
|
||||
{
|
||||
return _roles.GetRoles(int.Parse(siteid));
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(global))
|
||||
{
|
||||
global = "False";
|
||||
}
|
||||
return _roles.GetRoles(SiteId, bool.Parse(global));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Role Get(int id)
|
||||
{
|
||||
return _roles.GetRole(id);
|
||||
var role = _roles.GetRole(id);
|
||||
if (role != null && role.SiteId == _alias.SiteId)
|
||||
{
|
||||
return role;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Get Attempt {RoleId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
@ -42,11 +69,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Role Post([FromBody] Role role)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && role.SiteId == _alias.SiteId)
|
||||
{
|
||||
role = _roles.AddRole(role);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Role Added {Role}", role);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Post Attempt {Role}", role);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
role = null;
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
@ -55,11 +88,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Role Put(int id, [FromBody] Role role)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && role.SiteId == _alias.SiteId && _roles.GetRole(role.RoleId, false) != null)
|
||||
{
|
||||
role = _roles.UpdateRole(role);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Role Updated {Role}", role);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Put Attempt {Role}", role);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
role = null;
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
@ -68,8 +107,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
_roles.DeleteRole(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Role Deleted {RoleId}", id);
|
||||
var role = _roles.GetRole(id);
|
||||
if (role != null && !role.IsSystem && role.SiteId == _alias.SiteId)
|
||||
{
|
||||
_roles.DeleteRole(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Role Deleted {RoleId}", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Delete Attempt {RoleId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,27 +7,28 @@ using System.Linq;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class SettingController : Controller
|
||||
{
|
||||
private readonly ISettingRepository _settings;
|
||||
private readonly IPageModuleRepository _pageModules;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ITenantResolver _tenants;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger)
|
||||
public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_settings = settings;
|
||||
_pageModules = pageModules;
|
||||
_userPermissions = userPermissions;
|
||||
_tenants = tenants;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>
|
||||
@ -42,7 +43,7 @@ namespace Oqtane.Controllers
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Settings {EntityName} {EntityId}", entityname, entityid);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
@ -59,7 +60,7 @@ namespace Oqtane.Controllers
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Setting {Setting}", setting);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -73,14 +74,14 @@ namespace Oqtane.Controllers
|
||||
setting = _settings.AddSetting(setting);
|
||||
if (setting.EntityName == EntityNames.Module)
|
||||
{
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
}
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Setting Added {Setting}", setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Setting {Setting}", setting);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
setting = null;
|
||||
}
|
||||
return setting;
|
||||
@ -95,14 +96,14 @@ namespace Oqtane.Controllers
|
||||
setting = _settings.UpdateSetting(setting);
|
||||
if (setting.EntityName == EntityNames.Module)
|
||||
{
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
}
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Setting Updated {Setting}", setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Setting {Setting}", setting);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
setting = null;
|
||||
}
|
||||
return setting;
|
||||
@ -118,14 +119,14 @@ namespace Oqtane.Controllers
|
||||
_settings.DeleteSetting(id);
|
||||
if (setting.EntityName == EntityNames.Module)
|
||||
{
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
}
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Setting Deleted {Setting}", setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete Setting {Setting}", setting);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Models;
|
||||
@ -7,23 +7,24 @@ using System.Linq;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class SiteController : Controller
|
||||
{
|
||||
private readonly ISiteRepository _sites;
|
||||
private readonly ITenantResolver _tenants;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public SiteController(ISiteRepository sites, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger)
|
||||
public SiteController(ISiteRepository sites, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_sites = sites;
|
||||
_tenants = tenants;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>
|
||||
@ -38,7 +39,17 @@ namespace Oqtane.Controllers
|
||||
[HttpGet("{id}")]
|
||||
public Site Get(int id)
|
||||
{
|
||||
return _sites.GetSite(id);
|
||||
var site = _sites.GetSite(id);
|
||||
if (site.SiteId == _alias.SiteId)
|
||||
{
|
||||
return site;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Get Attempt {SiteId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
@ -52,8 +63,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
// provision initial site during installation
|
||||
authorized = true;
|
||||
Tenant tenant = _tenants.GetTenant();
|
||||
site.TenantId = tenant.TenantId;
|
||||
site.TenantId = _alias.TenantId;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -73,12 +83,18 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Site Put(int id, [FromBody] Site site)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && site.SiteId == _alias.SiteId && site.TenantId == _alias.TenantId && _sites.GetSite(site.SiteId, false) != null)
|
||||
{
|
||||
site = _sites.UpdateSite(site);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, site.SiteId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId);
|
||||
_logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Update, "Site Updated {Site}", site);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Put Attempt {Site}", site);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
site = null;
|
||||
}
|
||||
return site;
|
||||
}
|
||||
|
||||
@ -87,8 +103,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
_sites.DeleteSite(id);
|
||||
_logger.Log(id, LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", id);
|
||||
var site = _sites.GetSite(id);
|
||||
if (site != null && site.SiteId == _alias.SiteId)
|
||||
{
|
||||
_sites.DeleteSite(id);
|
||||
_logger.Log(id, LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Delete Attempt {SiteId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Oqtane.Models;
|
||||
@ -7,7 +7,7 @@ using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class SiteTemplateController : Controller
|
||||
{
|
||||
private readonly ISiteTemplateRepository _siteTemplates;
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
@ -7,11 +7,11 @@ using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Enums;
|
||||
using System;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Data;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class SqlController : Controller
|
||||
{
|
||||
private readonly ITenantRepository _tenants;
|
||||
@ -37,7 +37,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
foreach (string query in sqlquery.Query.Split("GO", StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
SqlDataReader dr = _sql.ExecuteReader(tenant, query);
|
||||
IDataReader dr = _sql.ExecuteReader(tenant, query);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Other, "Sql Query {Query} Executed on Tenant {TenantId}", query, sqlquery.TenantId);
|
||||
while (dr.Read())
|
||||
{
|
||||
@ -52,7 +52,7 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Other, "Sql Query {Query} Executed on Tenant {TenantId} Results In An Error {Error}", sqlquery.Query, sqlquery.TenantId, ex.Message);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Other, "Sql Query {Query} Executed on Tenant {TenantId} Resulted In An Error {Error}", sqlquery.Query, sqlquery.TenantId, ex.Message);
|
||||
}
|
||||
sqlquery.Results = results;
|
||||
return sqlquery;
|
||||
|
34
Oqtane.Server/Controllers/SyncController.cs
Normal file
34
Oqtane.Server/Controllers/SyncController.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Oqtane.Infrastructure;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class SyncController : Controller
|
||||
{
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public SyncController(ISyncManager syncManager, ITenantManager tenantManager)
|
||||
{
|
||||
_syncManager = syncManager;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET api/<controller>/yyyyMMddHHmmssfff
|
||||
[HttpGet("{lastSyncDate}")]
|
||||
public Sync Get(string lastSyncDate)
|
||||
{
|
||||
Sync sync = new Sync
|
||||
{
|
||||
SyncDate = DateTime.UtcNow,
|
||||
SyncEvents = _syncManager.GetSyncEvents(_alias.TenantId, DateTime.ParseExact(lastSyncDate, "yyyyMMddHHmmssfff", CultureInfo.InvariantCulture))
|
||||
};
|
||||
return sync;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,23 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Shared;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Oqtane.Infrastructure;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class SystemController : Controller
|
||||
{
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly IConfigManager _configManager;
|
||||
|
||||
public SystemController(IWebHostEnvironment environment)
|
||||
public SystemController(IWebHostEnvironment environment, IConfigManager configManager)
|
||||
{
|
||||
_environment = environment;
|
||||
_configManager = configManager;
|
||||
}
|
||||
|
||||
// GET: api/<controller>
|
||||
@ -23,13 +26,34 @@ namespace Oqtane.Controllers
|
||||
public Dictionary<string, string> Get()
|
||||
{
|
||||
Dictionary<string, string> systeminfo = new Dictionary<string, string>();
|
||||
|
||||
systeminfo.Add("rendermode", _configManager.GetSetting("RenderMode", "Server"));
|
||||
systeminfo.Add("clrversion", Environment.Version.ToString());
|
||||
systeminfo.Add("osversion", Environment.OSVersion.ToString());
|
||||
systeminfo.Add("machinename", Environment.MachineName);
|
||||
systeminfo.Add("serverpath", _environment.ContentRootPath);
|
||||
systeminfo.Add("servertime", DateTime.Now.ToString());
|
||||
|
||||
return systeminfo;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public void Post([FromBody] Dictionary<string, string> settings)
|
||||
{
|
||||
foreach(KeyValuePair<string, string> kvp in settings)
|
||||
{
|
||||
switch (kvp.Key)
|
||||
{
|
||||
case "runtime":
|
||||
_configManager.AddOrUpdateSetting("Runtime", kvp.Value, false);
|
||||
break;
|
||||
case "rendermode":
|
||||
_configManager.AddOrUpdateSetting("RenderMode", kvp.Value, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
@ -9,7 +9,7 @@ using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class TenantController : Controller
|
||||
{
|
||||
private readonly ITenantRepository _tenants;
|
||||
@ -23,7 +23,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public IEnumerable<Tenant> Get()
|
||||
{
|
||||
return _tenants.GetTenants();
|
||||
@ -31,7 +31,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public Tenant Get(int id)
|
||||
{
|
||||
return _tenants.GetTenant(id);
|
||||
|
@ -16,7 +16,7 @@ using System.Text.Json;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class ThemeController : Controller
|
||||
{
|
||||
private readonly IThemeRepository _themes;
|
||||
@ -45,7 +45,7 @@ namespace Oqtane.Controllers
|
||||
public void InstallThemes()
|
||||
{
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Themes Installed");
|
||||
_installationManager.InstallPackages("Themes");
|
||||
_installationManager.InstallPackages();
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/xxx
|
||||
@ -58,25 +58,8 @@ namespace Oqtane.Controllers
|
||||
if (theme != null && Utilities.GetAssemblyName(theme.ThemeName) != "Oqtane.Client")
|
||||
{
|
||||
// remove theme assets
|
||||
string assetpath = Path.Combine(_environment.WebRootPath, "Themes", Utilities.GetTypeName(theme.ThemeName));
|
||||
if (System.IO.File.Exists(Path.Combine(assetpath, "assets.json")))
|
||||
if (_installationManager.UninstallPackage(theme.PackageName))
|
||||
{
|
||||
// use assets.json to clean up file resources
|
||||
List<string> assets = JsonSerializer.Deserialize<List<string>>(System.IO.File.ReadAllText(Path.Combine(assetpath, "assets.json")));
|
||||
assets.Reverse();
|
||||
foreach (string asset in assets)
|
||||
{
|
||||
// legacy support for assets that were stored as absolute paths
|
||||
string filepath = (asset.StartsWith("\\")) ? Path.Combine(_environment.ContentRootPath, asset.Substring(1)) : asset;
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
System.IO.File.Delete(filepath);
|
||||
if (!Directory.EnumerateFiles(Path.GetDirectoryName(filepath)).Any())
|
||||
{
|
||||
Directory.Delete(Path.GetDirectoryName(filepath));
|
||||
}
|
||||
}
|
||||
}
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Assets Removed For {ThemeName}", theme.ThemeName);
|
||||
}
|
||||
else
|
||||
@ -90,10 +73,10 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
|
||||
// clean up theme static resource folder
|
||||
string folder = Path.Combine(_environment.WebRootPath, "Themes" , Utilities.GetTypeName(theme.ThemeName));
|
||||
if (Directory.Exists(folder))
|
||||
string assetpath = Path.Combine(_environment.WebRootPath, "Themes", Utilities.GetTypeName(theme.ThemeName));
|
||||
if (Directory.Exists(assetpath))
|
||||
{
|
||||
Directory.Delete(folder, true);
|
||||
Directory.Delete(assetpath, true);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Static Resource Folder Removed For {ThemeName}", theme.ThemeName);
|
||||
}
|
||||
|
||||
@ -106,13 +89,29 @@ namespace Oqtane.Controllers
|
||||
// GET: api/<controller>/templates
|
||||
[HttpGet("templates")]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public List<string> GetTemplates()
|
||||
public List<Template> GetTemplates()
|
||||
{
|
||||
var templates = new List<string>();
|
||||
var templates = new List<Template>();
|
||||
var root = Directory.GetParent(_environment.ContentRootPath);
|
||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", Path.DirectorySeparatorChar.ToString());
|
||||
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||
{
|
||||
templates.Add(directory.Replace(templatePath, ""));
|
||||
string name = directory.Replace(templatePath, "");
|
||||
if (System.IO.File.Exists(Path.Combine(directory, "template.json")))
|
||||
{
|
||||
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(Path.Combine(directory, "template.json")));
|
||||
template.Name = name;
|
||||
template.Location = "";
|
||||
if (template.Type.ToLower() != "internal")
|
||||
{
|
||||
template.Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString());
|
||||
}
|
||||
templates.Add(template);
|
||||
}
|
||||
else
|
||||
{
|
||||
templates.Add(new Template { Name = name, Title = name, Type = "External", Version = "", Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString()) });
|
||||
}
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
@ -128,8 +127,16 @@ namespace Oqtane.Controllers
|
||||
DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath);
|
||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", theme.Template, Path.DirectorySeparatorChar.ToString());
|
||||
|
||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, theme.Owner + "." + theme.Name, Path.DirectorySeparatorChar.ToString());
|
||||
theme.ThemeName = theme.Owner + "." + theme.Name + ", " + theme.Owner + "." + theme.Name + ".Client.Oqtane";
|
||||
if (theme.Template.ToLower().Contains("internal"))
|
||||
{
|
||||
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
||||
theme.ThemeName = theme.Owner + "." + theme.Name + ", Oqtane.Client";
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, theme.Owner + "." + theme.Name, Path.DirectorySeparatorChar.ToString());
|
||||
theme.ThemeName = theme.Owner + "." + theme.Name + ", " + theme.Owner + "." + theme.Name + ".Client.Oqtane";
|
||||
}
|
||||
|
||||
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, theme);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Theme Created {Theme}", theme);
|
||||
|
@ -18,7 +18,7 @@ using Oqtane.Extensions;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class UserController : Controller
|
||||
{
|
||||
private readonly IUserRepository _users;
|
||||
@ -26,26 +26,26 @@ namespace Oqtane.Controllers
|
||||
private readonly IUserRoleRepository _userRoles;
|
||||
private readonly UserManager<IdentityUser> _identityUserManager;
|
||||
private readonly SignInManager<IdentityUser> _identitySignInManager;
|
||||
private readonly ITenantResolver _tenants;
|
||||
private readonly INotificationRepository _notifications;
|
||||
private readonly IFolderRepository _folders;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ISiteRepository _sites;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public UserController(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantResolver tenants, INotificationRepository notifications, IFolderRepository folders, ISyncManager syncManager, ISiteRepository sites, ILogManager logger)
|
||||
public UserController(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, ISyncManager syncManager, ISiteRepository sites, ILogManager logger)
|
||||
{
|
||||
_users = users;
|
||||
_roles = roles;
|
||||
_userRoles = userRoles;
|
||||
_identityUserManager = identityUserManager;
|
||||
_identitySignInManager = identitySignInManager;
|
||||
_tenants = tenants;
|
||||
_folders = folders;
|
||||
_notifications = notifications;
|
||||
_syncManager = syncManager;
|
||||
_sites = sites;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET api/<controller>/5?siteid=x
|
||||
@ -53,26 +53,46 @@ namespace Oqtane.Controllers
|
||||
[Authorize]
|
||||
public User Get(int id, string siteid)
|
||||
{
|
||||
User user = _users.GetUser(id);
|
||||
if (user != null)
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
user.SiteId = int.Parse(siteid);
|
||||
user.Roles = GetUserRoles(user.UserId, user.SiteId);
|
||||
User user = _users.GetUser(id);
|
||||
if (user != null)
|
||||
{
|
||||
user.SiteId = int.Parse(siteid);
|
||||
user.Roles = GetUserRoles(user.UserId, user.SiteId);
|
||||
}
|
||||
return Filter(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Get Attempt {UserId} {SiteId}", id, siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
return Filter(user);
|
||||
}
|
||||
|
||||
// GET api/<controller>/name/x?siteid=x
|
||||
[HttpGet("name/{name}")]
|
||||
public User Get(string name, string siteid)
|
||||
{
|
||||
User user = _users.GetUser(name);
|
||||
if (user != null)
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
user.SiteId = int.Parse(siteid);
|
||||
user.Roles = GetUserRoles(user.UserId, user.SiteId);
|
||||
User user = _users.GetUser(name);
|
||||
if (user != null)
|
||||
{
|
||||
user.SiteId = int.Parse(siteid);
|
||||
user.Roles = GetUserRoles(user.UserId, user.SiteId);
|
||||
}
|
||||
return Filter(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Get Attempt {Username} {SiteId}", name, siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
return Filter(user);
|
||||
}
|
||||
|
||||
private User Filter(User user)
|
||||
@ -102,13 +122,18 @@ namespace Oqtane.Controllers
|
||||
[HttpPost]
|
||||
public async Task<User> Post([FromBody] User user)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && user.SiteId == _alias.SiteId)
|
||||
{
|
||||
var newUser = await CreateUser(user);
|
||||
return newUser;
|
||||
var User = await CreateUser(user);
|
||||
return User;
|
||||
}
|
||||
else
|
||||
{
|
||||
user.Password = ""; // remove sensitive information
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Post Attempt {User}", user);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<User> CreateUser(User user)
|
||||
@ -146,7 +171,7 @@ namespace Oqtane.Controllers
|
||||
if (!verified)
|
||||
{
|
||||
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
string url = HttpContext.Request.Scheme + "://" + _tenants.GetAlias().Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string url = HttpContext.Request.Scheme + "://" + _alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string body = "Dear " + user.DisplayName + ",\n\nIn Order To Complete The Registration Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
||||
var notification = new Notification(user.SiteId, null, newUser, "User Account Verification", body, null);
|
||||
_notifications.AddNotification(notification);
|
||||
@ -173,6 +198,7 @@ namespace Oqtane.Controllers
|
||||
SiteId = folder.SiteId,
|
||||
ParentId = folder.FolderId,
|
||||
Name = "My Folder",
|
||||
Type = FolderTypes.Private,
|
||||
Path = Utilities.PathCombine(folder.Path, newUser.UserId.ToString(),Path.DirectorySeparatorChar.ToString()),
|
||||
Order = 1,
|
||||
IsSystem = true,
|
||||
@ -229,30 +255,28 @@ namespace Oqtane.Controllers
|
||||
[Authorize]
|
||||
public async Task<User> Put(int id, [FromBody] User user)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (ModelState.IsValid && user.SiteId == _alias.SiteId && _users.GetUser(user.UserId, false) != null && (User.IsInRole(RoleNames.Admin) || User.Identity.Name == user.Username))
|
||||
{
|
||||
if (User.IsInRole(RoleNames.Admin) || User.Identity.Name == user.Username)
|
||||
if (user.Password != "")
|
||||
{
|
||||
if (user.Password != "")
|
||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||
if (identityuser != null)
|
||||
{
|
||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||
if (identityuser != null)
|
||||
{
|
||||
identityuser.PasswordHash = _identityUserManager.PasswordHasher.HashPassword(identityuser, user.Password);
|
||||
await _identityUserManager.UpdateAsync(identityuser);
|
||||
}
|
||||
identityuser.PasswordHash = _identityUserManager.PasswordHasher.HashPassword(identityuser, user.Password);
|
||||
await _identityUserManager.UpdateAsync(identityuser);
|
||||
}
|
||||
user = _users.UpdateUser(user);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.User, user.UserId);
|
||||
user.Password = ""; // remove sensitive information
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update User {User}", user);
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
user = null;
|
||||
}
|
||||
user = _users.UpdateUser(user);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, user.UserId);
|
||||
user.Password = ""; // remove sensitive information
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
|
||||
}
|
||||
else
|
||||
{
|
||||
user.Password = ""; // remove sensitive information
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Post Attempt {User}", user);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
user = null;
|
||||
}
|
||||
return user;
|
||||
}
|
||||
@ -262,18 +286,19 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public async Task Delete(int id, string siteid)
|
||||
{
|
||||
int SiteId;
|
||||
User user = _users.GetUser(id);
|
||||
if (user != null)
|
||||
if (user != null && int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
// remove user roles for site
|
||||
foreach (UserRole userrole in _userRoles.GetUserRoles(user.UserId, Int32.Parse(siteid)).ToList())
|
||||
foreach (UserRole userrole in _userRoles.GetUserRoles(user.UserId, SiteId).ToList())
|
||||
{
|
||||
_userRoles.DeleteUserRole(userrole.UserRoleId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userrole);
|
||||
}
|
||||
|
||||
// remove user folder for site
|
||||
var folder = _folders.GetFolder(Int32.Parse(siteid), Utilities.PathCombine("Users", user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()));
|
||||
var folder = _folders.GetFolder(SiteId, Utilities.PathCombine("Users", user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()));
|
||||
if (folder != null)
|
||||
{
|
||||
if (Directory.Exists(_folders.GetFolderPath(folder)))
|
||||
@ -306,6 +331,11 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Delete Attempt {UserId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>/login
|
||||
@ -358,7 +388,7 @@ namespace Oqtane.Controllers
|
||||
[Authorize]
|
||||
public async Task Logout([FromBody] User user)
|
||||
{
|
||||
await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);
|
||||
await HttpContext.SignOutAsync(Constants.AuthenticationScheme);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Logout {Username}", (user != null) ? user.Username : "");
|
||||
}
|
||||
|
||||
@ -401,7 +431,7 @@ namespace Oqtane.Controllers
|
||||
if (identityuser != null)
|
||||
{
|
||||
string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser);
|
||||
string url = HttpContext.Request.Scheme + "://" + _tenants.GetAlias().Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string url = HttpContext.Request.Scheme + "://" + _alias.Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string body = "Dear " + user.DisplayName + ",\n\nPlease Click The Link Displayed Below To Reset Your Password:\n\n" + url + "\n\nThank You!";
|
||||
var notification = new Notification(user.SiteId, null, user, "User Password Reset", body, null);
|
||||
_notifications.AddNotification(notification);
|
||||
@ -444,7 +474,7 @@ namespace Oqtane.Controllers
|
||||
return user;
|
||||
}
|
||||
|
||||
// GET api/<controller>/current
|
||||
// GET api/<controller>/authenticate
|
||||
[HttpGet("authenticate")]
|
||||
public User Authenticate()
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Enums;
|
||||
@ -6,23 +6,27 @@ using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class UserRoleController : Controller
|
||||
{
|
||||
private readonly IUserRoleRepository _userRoles;
|
||||
private readonly ITenantResolver _tenants;
|
||||
private readonly IRoleRepository _roles;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public UserRoleController(IUserRoleRepository userRoles, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger)
|
||||
public UserRoleController(IUserRoleRepository userRoles, IRoleRepository roles, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_userRoles = userRoles;
|
||||
_roles = roles;
|
||||
_syncManager = syncManager;
|
||||
_tenants = tenants;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
@ -30,7 +34,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public IEnumerable<UserRole> Get(string siteid)
|
||||
{
|
||||
return _userRoles.GetUserRoles(int.Parse(siteid));
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return _userRoles.GetUserRoles(SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UserRole Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
@ -38,7 +52,17 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public UserRole Get(int id)
|
||||
{
|
||||
return _userRoles.GetUserRole(id);
|
||||
var userrole = _userRoles.GetUserRole(id);
|
||||
if (userrole != null && userrole.Role.SiteId == _alias.SiteId)
|
||||
{
|
||||
return userrole;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Role Get Attempt {UserRoleId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
@ -46,11 +70,26 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public UserRole Post([FromBody] UserRole userRole)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
var role = _roles.GetRole(userRole.RoleId);
|
||||
if (ModelState.IsValid && role != null && role.SiteId == _alias.SiteId && (User.IsInRole(RoleNames.Host) || role.Name != RoleNames.Host))
|
||||
{
|
||||
if (role.Name == RoleNames.Host)
|
||||
{
|
||||
// host roles can only exist at global level - remove all site specific user roles
|
||||
_userRoles.DeleteUserRoles(userRole.UserId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Roles Deleted For UserId {UserId}", userRole.UserId);
|
||||
}
|
||||
|
||||
userRole = _userRoles.AddUserRole(userRole);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.User, userRole.UserId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole);
|
||||
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UserRole Post Attempt {UserRole}", userRole);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
userRole = null;
|
||||
}
|
||||
return userRole;
|
||||
}
|
||||
@ -60,12 +99,19 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public UserRole Put(int id, [FromBody] UserRole userRole)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
var role = _roles.GetRole(userRole.RoleId);
|
||||
if (ModelState.IsValid && role != null && role.SiteId == _alias.SiteId && _userRoles.GetUserRole(userRole.UserRoleId, false) != null && (User.IsInRole(RoleNames.Host) || role.Name != RoleNames.Host))
|
||||
{
|
||||
userRole = _userRoles.UpdateUserRole(userRole);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.User, userRole.UserId);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Role Updated {UserRole}", userRole);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Role Put Attempt {UserRole}", userRole);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
userRole = null;
|
||||
}
|
||||
return userRole;
|
||||
}
|
||||
|
||||
@ -75,9 +121,29 @@ namespace Oqtane.Controllers
|
||||
public void Delete(int id)
|
||||
{
|
||||
UserRole userRole = _userRoles.GetUserRole(id);
|
||||
_userRoles.DeleteUserRole(id);
|
||||
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.User, userRole.UserId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userRole);
|
||||
if (userRole != null && userRole.Role.SiteId == _alias.SiteId && (User.IsInRole(RoleNames.Host) || userRole.Role.Name != RoleNames.Host))
|
||||
{
|
||||
_userRoles.DeleteUserRole(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userRole);
|
||||
|
||||
if (userRole.Role.Name == RoleNames.Host)
|
||||
{
|
||||
// add site specific user roles to preserve user access
|
||||
var role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Registered);
|
||||
userRole = _userRoles.AddUserRole(new UserRole { UserId = userRole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole);
|
||||
role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Admin);
|
||||
userRole = _userRoles.AddUserRole(new UserRole { UserId = userRole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole);
|
||||
}
|
||||
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Role Delete Attempt {UserRoleId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
75
Oqtane.Server/Databases/DatabaseBase.cs
Normal file
75
Oqtane.Server/Databases/DatabaseBase.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
|
||||
namespace Oqtane.Databases
|
||||
{
|
||||
public abstract class DatabaseBase : IDatabase
|
||||
{
|
||||
private static string _assemblyName;
|
||||
|
||||
private static string _typeName;
|
||||
|
||||
protected DatabaseBase(string name, string friendlyName)
|
||||
{
|
||||
Name = name;
|
||||
FriendlyName = friendlyName;
|
||||
}
|
||||
|
||||
protected static void Initialize(Type type)
|
||||
{
|
||||
var typeQualifiedName = type.AssemblyQualifiedName;
|
||||
var assembly = type.Assembly;
|
||||
var assemblyName = assembly.FullName;
|
||||
|
||||
_typeName = typeQualifiedName.Substring(0, typeQualifiedName.IndexOf(", Version"));
|
||||
_assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(", Version"));
|
||||
}
|
||||
|
||||
public string AssemblyName => _assemblyName;
|
||||
|
||||
public string FriendlyName { get; }
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public abstract string Provider { get; }
|
||||
|
||||
public string TypeName => _typeName;
|
||||
|
||||
public abstract OperationBuilder<AddColumnOperation> AddAutoIncrementColumn(ColumnsBuilder table, string name);
|
||||
|
||||
public virtual string ConcatenateSql(params string[] values)
|
||||
{
|
||||
var returnValue = String.Empty;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
returnValue += " + ";
|
||||
}
|
||||
returnValue += values[i];
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public abstract int ExecuteNonQuery(string connectionString, string query);
|
||||
|
||||
public abstract IDataReader ExecuteReader(string connectionString, string query);
|
||||
|
||||
public virtual string RewriteName(string name)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public virtual void UpdateIdentityStoreTableNames(ModelBuilder builder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public abstract DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString);
|
||||
}
|
||||
}
|
34
Oqtane.Server/Databases/Interfaces/IDatabase.cs
Normal file
34
Oqtane.Server/Databases/Interfaces/IDatabase.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
|
||||
namespace Oqtane.Databases.Interfaces
|
||||
{
|
||||
public interface IDatabase
|
||||
{
|
||||
public string AssemblyName { get; }
|
||||
|
||||
public string FriendlyName { get; }
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public string Provider { get; }
|
||||
|
||||
public string TypeName { get; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> AddAutoIncrementColumn(ColumnsBuilder table, string name);
|
||||
|
||||
public string ConcatenateSql(params string[] values);
|
||||
|
||||
public int ExecuteNonQuery(string connectionString, string query);
|
||||
|
||||
public IDataReader ExecuteReader(string connectionString, string query);
|
||||
|
||||
public string RewriteName(string name);
|
||||
|
||||
public void UpdateIdentityStoreTableNames(ModelBuilder builder);
|
||||
|
||||
public DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString);
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
namespace Oqtane.Repository.Databases.Interfaces
|
||||
{
|
||||
public interface IMultiDatabase
|
||||
{
|
||||
public IEnumerable<IOqtaneDatabase> Databases { get; }
|
||||
public IDatabase ActiveDatabase { get; }
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository.Databases;
|
||||
|
||||
namespace Oqtane.Databases
|
||||
{
|
||||
public class LocalDbDatabase : SqlServerDatabaseBase
|
||||
{
|
||||
private static string _friendlyName => "Local Database";
|
||||
private static string _name => "LocalDB";
|
||||
|
||||
private static readonly List<ConnectionStringField> _connectionStringFields = new()
|
||||
{
|
||||
new() {Name = "Server", FriendlyName = "Server", Value = "(LocalDb)\\MSSQLLocalDB", HelpText="Enter the database server"},
|
||||
new() {Name = "Database", FriendlyName = "Database", Value = "Oqtane-{{Date}}", HelpText="Enter the name of the database"}
|
||||
};
|
||||
|
||||
public LocalDbDatabase() :base(_name, _friendlyName, _connectionStringFields) { }
|
||||
|
||||
public override string BuildConnectionString()
|
||||
{
|
||||
var connectionString = String.Empty;
|
||||
|
||||
var server = ConnectionStringFields[0].Value;
|
||||
var database = ConnectionStringFields[1].Value;
|
||||
|
||||
if (!String.IsNullOrEmpty(server) && !String.IsNullOrEmpty(database))
|
||||
{
|
||||
connectionString = $"Data Source={server};AttachDbFilename=|DataDirectory|\\{database}.mdf;Initial Catalog={database};Integrated Security=SSPI;";
|
||||
}
|
||||
|
||||
return connectionString;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository.Databases;
|
||||
|
||||
// ReSharper disable ArrangeObjectCreationWhenTypeNotEvident
|
||||
|
||||
namespace Oqtane.Databases
|
||||
{
|
||||
public class SqlServerDatabase : SqlServerDatabaseBase
|
||||
{
|
||||
private static string _friendlyName => "SQL Server";
|
||||
|
||||
private static string _name => "SqlServer";
|
||||
|
||||
private static readonly List<ConnectionStringField> _connectionStringFields = new()
|
||||
{
|
||||
new() {Name = "Server", FriendlyName = "Server", Value = ".", HelpText="Enter the database server"},
|
||||
new() {Name = "Database", FriendlyName = "Database", Value = "Oqtane-{{Date}}", HelpText="Enter the name of the database"},
|
||||
new() {Name = "IntegratedSecurity", FriendlyName = "Integrated Security", Value = "true", HelpText="Select if you want integrated security or not"},
|
||||
new() {Name = "Uid", FriendlyName = "User Id", Value = "", HelpText="Enter the username to use for the database"},
|
||||
new() {Name = "Pwd", FriendlyName = "Password", Value = "", HelpText="Enter the password to use for the database"}
|
||||
};
|
||||
|
||||
public SqlServerDatabase() :base(_name, _friendlyName, _connectionStringFields) { }
|
||||
|
||||
public override string BuildConnectionString()
|
||||
{
|
||||
var connectionString = String.Empty;
|
||||
|
||||
var server = ConnectionStringFields[0].Value;
|
||||
var database = ConnectionStringFields[1].Value;
|
||||
var integratedSecurity = Boolean.Parse(ConnectionStringFields[2].Value);
|
||||
var userId = ConnectionStringFields[3].Value;
|
||||
var password = ConnectionStringFields[4].Value;
|
||||
|
||||
if (!String.IsNullOrEmpty(server) && !String.IsNullOrEmpty(database))
|
||||
{
|
||||
connectionString = $"Data Source={server};Initial Catalog={database};";
|
||||
}
|
||||
|
||||
if (integratedSecurity)
|
||||
{
|
||||
connectionString += "Integrated Security=SSPI;";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!String.IsNullOrEmpty(userId) && !String.IsNullOrEmpty(password))
|
||||
{
|
||||
connectionString += $"User ID={userId};Password={password};";
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionString = String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
return connectionString;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Repository.Databases
|
||||
{
|
||||
public abstract class SqlServerDatabaseBase : OqtaneDatabaseBase
|
||||
{
|
||||
protected SqlServerDatabaseBase(string name, string friendlyName, List<ConnectionStringField> connectionStringFields) : base(name, friendlyName, connectionStringFields)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Provider => "Microsoft.EntityFrameworkCore.SqlServer";
|
||||
|
||||
public override OperationBuilder<AddColumnOperation> AddAutoIncrementColumn(ColumnsBuilder table, string name)
|
||||
{
|
||||
return table.Column<int>(name: name, nullable: false).Annotation("SqlServer:Identity", "1, 1");
|
||||
}
|
||||
|
||||
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
||||
{
|
||||
return optionsBuilder.UseSqlServer(connectionString);
|
||||
}
|
||||
}
|
||||
}
|
@ -38,5 +38,8 @@ namespace Oqtane.Extensions
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseTenantResolution(this IApplicationBuilder builder)
|
||||
=> builder.UseMiddleware<TenantMiddleware>();
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,17 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
// ReSharper disable ConvertToUsingDeclaration
|
||||
|
||||
namespace Oqtane.Extensions
|
||||
{
|
||||
public static class DbContextOptionsBuilderExtensions
|
||||
{
|
||||
public static DbContextOptionsBuilder UseOqtaneDatabase([NotNull] this DbContextOptionsBuilder optionsBuilder, IOqtaneDatabase database, string connectionString)
|
||||
public static DbContextOptionsBuilder UseOqtaneDatabase([NotNull] this DbContextOptionsBuilder optionsBuilder, IDatabase database, string connectionString)
|
||||
{
|
||||
database.UseDatabase(optionsBuilder, connectionString);
|
||||
|
||||
return optionsBuilder;
|
||||
}
|
||||
|
||||
public static DbContextOptionsBuilder UseOqtaneDatabase([NotNull] this DbContextOptionsBuilder optionsBuilder, string databaseType, string connectionString)
|
||||
{
|
||||
var type = Type.GetType(databaseType);
|
||||
var database = Activator.CreateInstance(type) as IOqtaneDatabase;
|
||||
|
||||
database.UseDatabase(optionsBuilder, connectionString);
|
||||
|
||||
return optionsBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -200,17 +200,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
}
|
||||
}
|
||||
|
||||
// dynamically register database providers
|
||||
var databaseTypes = assembly.GetInterfaces<IOqtaneDatabase>();
|
||||
foreach (var databaseType in databaseTypes)
|
||||
{
|
||||
if (databaseType.AssemblyQualifiedName != null)
|
||||
{
|
||||
var serviceType = Type.GetType("Oqtane.Interfaces.IOqtaneDatabase, Oqtane.Shared");
|
||||
services.AddScoped(serviceType ?? databaseType, databaseType);
|
||||
}
|
||||
}
|
||||
|
||||
// dynamically register hosted services
|
||||
var serviceTypes = assembly.GetTypes(hostedServiceType);
|
||||
foreach (var serviceType in serviceTypes)
|
||||
@ -265,26 +254,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
|
||||
if (!assemblies.Any(a => AssemblyName.ReferenceMatchesDefinition(assemblyName, a.GetName())))
|
||||
{
|
||||
try
|
||||
{
|
||||
var pdb = Path.ChangeExtension(dll.FullName, ".pdb");
|
||||
Assembly assembly = null;
|
||||
|
||||
// load assembly ( and symbols ) from stream to prevent locking files ( as long as dependencies are in /bin they will load as well )
|
||||
if (File.Exists(pdb))
|
||||
{
|
||||
assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(dll.FullName)), new MemoryStream(File.ReadAllBytes(pdb)));
|
||||
}
|
||||
else
|
||||
{
|
||||
assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(dll.FullName)));
|
||||
}
|
||||
Console.WriteLine($"Loaded : {assemblyName}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Failed : {assemblyName}\n{e}");
|
||||
}
|
||||
AssemblyLoadContext.Default.LoadOqtaneAssembly(dll, assemblyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
115
Oqtane.Server/Infrastructure/ConfigManager.cs
Normal file
115
Oqtane.Server/Infrastructure/ConfigManager.cs
Normal file
@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class ConfigManager : IConfigManager
|
||||
{
|
||||
private readonly IConfigurationRoot _config;
|
||||
|
||||
public ConfigManager(IConfigurationRoot config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public IConfigurationSection GetSection(string key)
|
||||
{
|
||||
return _config.GetSection(key);
|
||||
}
|
||||
|
||||
public T GetSetting<T>(string sectionKey, T defaultValue)
|
||||
{
|
||||
return GetSetting(sectionKey, "", defaultValue);
|
||||
}
|
||||
|
||||
public T GetSetting<T>(string sectionKey, string settingKey, T defaultValue)
|
||||
{
|
||||
T value;
|
||||
if (!string.IsNullOrEmpty(settingKey))
|
||||
{
|
||||
value = _config.GetSection(sectionKey).GetValue(settingKey, defaultValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = _config.GetValue(sectionKey, defaultValue);
|
||||
}
|
||||
if (value == null) value = defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
public void AddOrUpdateSetting<T>(string key, T value, bool reload)
|
||||
{
|
||||
AddOrUpdateSetting("appsettings.json", key, value, reload);
|
||||
}
|
||||
|
||||
public void AddOrUpdateSetting<T>(string file, string key, T value, bool reload)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = Path.Combine(Directory.GetCurrentDirectory(), file);
|
||||
dynamic jsonObj = JsonConvert.DeserializeObject(File.ReadAllText(path));
|
||||
SetValueRecursively(key, jsonObj, value, "set");
|
||||
File.WriteAllText(path, JsonConvert.SerializeObject(jsonObj, Formatting.Indented));
|
||||
if (reload) Reload();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error modifying app settings {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveSetting(string key, bool reload)
|
||||
{
|
||||
RemoveSetting("appsettings.json", key, reload);
|
||||
}
|
||||
|
||||
public void RemoveSetting(string file, string key, bool reload)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = Path.Combine(Directory.GetCurrentDirectory(), file);
|
||||
dynamic jsonObj = JsonConvert.DeserializeObject(File.ReadAllText(path));
|
||||
SetValueRecursively(key, jsonObj, "", "remove");
|
||||
File.WriteAllText(path, JsonConvert.SerializeObject(jsonObj, Formatting.Indented));
|
||||
if (reload) Reload();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error modifying app settings {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValueRecursively<T>(string key, dynamic jsonObj, T value, string action)
|
||||
{
|
||||
var remainingSections = key.Split(":", 2);
|
||||
|
||||
var currentSection = remainingSections[0];
|
||||
if (remainingSections.Length > 1)
|
||||
{
|
||||
var nextSection = remainingSections[1];
|
||||
jsonObj[currentSection] ??= new JObject();
|
||||
SetValueRecursively(nextSection, jsonObj[currentSection], value, action);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case "set":
|
||||
jsonObj[currentSection] = value;
|
||||
break;
|
||||
case "remove":
|
||||
jsonObj.Property(currentSection).Remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
_config.Reload();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,19 +3,20 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Extensions;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Interfaces;
|
||||
using File = System.IO.File;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable ConvertToUsingDeclaration
|
||||
@ -28,24 +29,28 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
private readonly IConfigurationRoot _config;
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IConfigManager _configManager;
|
||||
|
||||
public DatabaseManager(IConfigurationRoot config, IServiceScopeFactory serviceScopeFactory, IMemoryCache cache)
|
||||
public DatabaseManager(IConfigurationRoot config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache, IConfigManager configManager)
|
||||
{
|
||||
_config = config;
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_environment = environment;
|
||||
_cache = cache;
|
||||
_configManager = configManager;
|
||||
}
|
||||
|
||||
public Installation IsInstalled()
|
||||
{
|
||||
var result = new Installation { Success = false, Message = string.Empty };
|
||||
|
||||
if (!string.IsNullOrEmpty(_config.GetConnectionString(SettingKeys.ConnectionStringKey)))
|
||||
{
|
||||
result.Success = true;
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
using (var db = GetInstallationContext())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<MasterDBContext>();
|
||||
if (db.Database.CanConnect())
|
||||
{
|
||||
try
|
||||
@ -75,6 +80,8 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
var result = new Installation { Success = false, Message = string.Empty };
|
||||
|
||||
ValidateConfiguration();
|
||||
|
||||
// get configuration
|
||||
if (install == null)
|
||||
{
|
||||
@ -87,6 +94,12 @@ namespace Oqtane.Infrastructure
|
||||
IsNewTenant = false
|
||||
};
|
||||
|
||||
// on upgrade install the associated Nuget package
|
||||
if (!string.IsNullOrEmpty(install.ConnectionString) && Type.GetType(install.DatabaseType) == null)
|
||||
{
|
||||
InstallDatabase(install);
|
||||
}
|
||||
|
||||
var installation = IsInstalled();
|
||||
if (!installation.Success)
|
||||
{
|
||||
@ -173,6 +186,61 @@ namespace Oqtane.Infrastructure
|
||||
return result;
|
||||
}
|
||||
|
||||
private Installation InstallDatabase(InstallConfig install)
|
||||
{
|
||||
var result = new Installation {Success = false, Message = string.Empty};
|
||||
|
||||
try
|
||||
{
|
||||
var databaseType = install.DatabaseType;
|
||||
|
||||
//Get database Type
|
||||
var type = Type.GetType(databaseType);
|
||||
|
||||
//Deploy the database components (if necessary)
|
||||
if (type == null)
|
||||
{
|
||||
//Rename bak extension
|
||||
var packageFolderName = "Packages";
|
||||
var path = _environment.ContentRootPath;
|
||||
var packagesFolder = new DirectoryInfo(Path.Combine(path, packageFolderName));
|
||||
|
||||
// iterate through Nuget packages in source folder
|
||||
foreach (var package in packagesFolder.GetFiles("*.nupkg.bak"))
|
||||
{
|
||||
if (package.Name.StartsWith(Utilities.GetAssemblyName(install.DatabaseType)))
|
||||
{
|
||||
//rename file
|
||||
var packageName = Path.Combine(package.DirectoryName, package.Name);
|
||||
packageName = packageName.Substring(0, packageName.IndexOf(".bak"));
|
||||
package.MoveTo(packageName, true);
|
||||
}
|
||||
}
|
||||
|
||||
//Call InstallationManager to install Database Package
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
var installationManager = scope.ServiceProvider.GetRequiredService<IInstallationManager>();
|
||||
installationManager.InstallPackages();
|
||||
|
||||
var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
var assembliesFolder = new DirectoryInfo(assemblyPath);
|
||||
var assemblyFile = new FileInfo($"{assembliesFolder}/{Utilities.GetAssemblyName(install.DatabaseType)}.dll");
|
||||
|
||||
AssemblyLoadContext.Default.LoadOqtaneAssembly(assemblyFile);
|
||||
|
||||
result.Success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Message = ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Installation CreateDatabase(InstallConfig install)
|
||||
{
|
||||
var result = new Installation { Success = false, Message = string.Empty };
|
||||
@ -181,22 +249,26 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
try
|
||||
{
|
||||
InstallDatabase(install);
|
||||
|
||||
var databaseType = install.DatabaseType;
|
||||
|
||||
//Get database Type
|
||||
var type = Type.GetType(databaseType);
|
||||
|
||||
//Create database object from Type
|
||||
var database = Activator.CreateInstance(type) as IDatabase;
|
||||
|
||||
//create data directory if does not exist
|
||||
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
|
||||
if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory ?? String.Empty);
|
||||
|
||||
var connectionString = NormalizeConnectionString(install.ConnectionString);
|
||||
var databaseType = install.DatabaseType;
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
var dbOptions = new DbContextOptionsBuilder().UseOqtaneDatabase(database, NormalizeConnectionString(install.ConnectionString)).Options;
|
||||
using (var dbc = new DbContext(dbOptions))
|
||||
{
|
||||
var databases = scope.ServiceProvider.GetServices<IOqtaneDatabase>();
|
||||
|
||||
using (var dbc = new DbContext(new DbContextOptionsBuilder().UseOqtaneDatabase(databases.Single(d => d.Name == databaseType), connectionString).Options))
|
||||
{
|
||||
// create empty database if it does not exist
|
||||
dbc.Database.EnsureCreated();
|
||||
result.Success = true;
|
||||
}
|
||||
// create empty database if it does not exist
|
||||
dbc.Database.EnsureCreated();
|
||||
result.Success = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -220,19 +292,19 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
var databases = scope.ServiceProvider.GetServices<IOqtaneDatabase>();
|
||||
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
|
||||
|
||||
var installation = IsInstalled();
|
||||
try
|
||||
{
|
||||
var dbConfig = new DbConfig(null, null, databases) {ConnectionString = install.ConnectionString, DatabaseType = install.DatabaseType};
|
||||
UpdateConnectionString(install.ConnectionString);
|
||||
UpdateDatabaseType(install.DatabaseType);
|
||||
|
||||
using (var masterDbContext = new MasterDBContext(new DbContextOptions<MasterDBContext>(), dbConfig))
|
||||
using (var masterDbContext = new MasterDBContext(new DbContextOptions<MasterDBContext>(), null, _config))
|
||||
{
|
||||
var installation = IsInstalled();
|
||||
if (installation.Success && (install.DatabaseType == "SqlServer" || install.DatabaseType == "LocalDB"))
|
||||
if (installation.Success && (install.DatabaseType == Constants.DefaultDBType))
|
||||
{
|
||||
UpgradeSqlServer(sql, install.ConnectionString, true);
|
||||
UpgradeSqlServer(sql, install.ConnectionString, install.DatabaseType, true);
|
||||
}
|
||||
// Push latest model into database
|
||||
masterDbContext.Database.Migrate();
|
||||
@ -243,12 +315,6 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
result.Message = ex.Message;
|
||||
}
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
UpdateConnectionString(install.ConnectionString);
|
||||
UpdateDatabaseType(install.DatabaseType);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -265,11 +331,7 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
if (!string.IsNullOrEmpty(install.TenantName) && !string.IsNullOrEmpty(install.Aliases))
|
||||
{
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
var databases = scope.ServiceProvider.GetServices<IOqtaneDatabase>();
|
||||
|
||||
using (var db = GetInstallationContext(databases))
|
||||
using (var db = GetInstallationContext())
|
||||
{
|
||||
Tenant tenant;
|
||||
if (install.IsNewTenant)
|
||||
@ -315,7 +377,6 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
_cache.Remove("aliases");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.Success = true;
|
||||
@ -332,21 +393,21 @@ namespace Oqtane.Infrastructure
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
var upgrades = scope.ServiceProvider.GetRequiredService<IUpgradeManager>();
|
||||
var databases = scope.ServiceProvider.GetServices<IOqtaneDatabase>();
|
||||
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
|
||||
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
|
||||
using (var db = GetInstallationContext(databases))
|
||||
using (var db = GetInstallationContext())
|
||||
{
|
||||
foreach (var tenant in db.Tenant.ToList())
|
||||
{
|
||||
tenantManager.SetTenant(tenant.TenantId);
|
||||
try
|
||||
{
|
||||
var dbConfig = new DbConfig(null, null, databases) {ConnectionString = tenant.DBConnectionString, DatabaseType = tenant.DBType};
|
||||
using (var tenantDbContext = new TenantDBContext(dbConfig, null))
|
||||
using (var tenantDbContext = new TenantDBContext(tenantManager, null))
|
||||
{
|
||||
if (install.DatabaseType == "SqlServer" || install.DatabaseType == "LocalDB")
|
||||
if (install.DatabaseType == Constants.DefaultDBType)
|
||||
{
|
||||
UpgradeSqlServer(sql, tenant.DBConnectionString, false);
|
||||
UpgradeSqlServer(sql, tenant.DBConnectionString, tenant.DBType, false);
|
||||
}
|
||||
|
||||
// Push latest model into database
|
||||
@ -393,7 +454,7 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
var moduleDefinitions = scope.ServiceProvider.GetRequiredService<IModuleDefinitionRepository>();
|
||||
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
|
||||
var databases = scope.ServiceProvider.GetServices<IOqtaneDatabase>();
|
||||
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
|
||||
foreach (var moduleDefinition in moduleDefinitions.GetModuleDefinitions())
|
||||
{
|
||||
@ -403,7 +464,7 @@ namespace Oqtane.Infrastructure
|
||||
if (moduleType != null)
|
||||
{
|
||||
var versions = moduleDefinition.ReleaseVersions.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
using (var db = GetInstallationContext(databases))
|
||||
using (var db = GetInstallationContext())
|
||||
{
|
||||
foreach (var tenant in db.Tenant.ToList())
|
||||
{
|
||||
@ -414,13 +475,13 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
if (index != (versions.Length - 1))
|
||||
{
|
||||
if (index == -1) index = 0;
|
||||
for (var i = index; i < versions.Length; i++)
|
||||
for (var i = (index + 1); i < versions.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (moduleType.GetInterface("IInstallable") != null)
|
||||
{
|
||||
tenantManager.SetTenant(tenant.TenantId);
|
||||
var moduleObject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduleType) as IInstallable;
|
||||
moduleObject?.Install(tenant, versions[i]);
|
||||
}
|
||||
@ -464,12 +525,12 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
// use the SiteState to set the Alias explicitly so the tenant can be resolved
|
||||
// set the alias explicitly so the tenant can be resolved
|
||||
var aliases = scope.ServiceProvider.GetRequiredService<IAliasRepository>();
|
||||
var firstAlias = install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
|
||||
var alias = aliases.GetAliases().FirstOrDefault(item => item.Name == firstAlias);
|
||||
var siteState = scope.ServiceProvider.GetRequiredService<SiteState>();
|
||||
siteState.Alias = alias;
|
||||
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
tenantManager.SetAlias(alias);
|
||||
|
||||
var sites = scope.ServiceProvider.GetRequiredService<ISiteRepository>();
|
||||
var site = sites.GetSites().FirstOrDefault(item => item.Name == install.SiteName);
|
||||
@ -490,8 +551,9 @@ namespace Oqtane.Infrastructure
|
||||
TenantId = tenant.TenantId,
|
||||
Name = install.SiteName,
|
||||
LogoFileId = null,
|
||||
DefaultThemeType = install.DefaultTheme,
|
||||
DefaultContainerType = install.DefaultContainer,
|
||||
DefaultThemeType = (!string.IsNullOrEmpty(install.DefaultTheme)) ? install.DefaultTheme : Constants.DefaultTheme,
|
||||
DefaultContainerType = (!string.IsNullOrEmpty(install.DefaultContainer)) ? install.DefaultContainer : Constants.DefaultContainer,
|
||||
AdminContainerType = (!string.IsNullOrEmpty(install.DefaultAdminContainer)) ? install.DefaultAdminContainer : Constants.DefaultAdminContainer,
|
||||
SiteTemplateType = install.SiteTemplate
|
||||
};
|
||||
site = sites.AddSite(site);
|
||||
@ -528,6 +590,7 @@ namespace Oqtane.Infrastructure
|
||||
SiteId = folder.SiteId,
|
||||
ParentId = folder.FolderId,
|
||||
Name = "My Folder",
|
||||
Type = FolderTypes.Private,
|
||||
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()),
|
||||
Order = 1,
|
||||
IsSystem = true,
|
||||
@ -565,25 +628,6 @@ namespace Oqtane.Infrastructure
|
||||
return result;
|
||||
}
|
||||
|
||||
public void AddOrUpdateAppSetting<T>(string sectionPathKey, T value)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json");
|
||||
var json = File.ReadAllText(filePath);
|
||||
dynamic jsonObj = JsonConvert.DeserializeObject(json);
|
||||
|
||||
SetValueRecursively(sectionPathKey, jsonObj, value);
|
||||
|
||||
string output = JsonConvert.SerializeObject(jsonObj, Formatting.Indented);
|
||||
File.WriteAllText(filePath, output);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error writing app settings | {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private string DenormalizeConnectionString(string connectionString)
|
||||
{
|
||||
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
|
||||
@ -591,20 +635,24 @@ namespace Oqtane.Infrastructure
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
private InstallationContext GetInstallationContext(IEnumerable<IOqtaneDatabase> databases)
|
||||
private InstallationContext GetInstallationContext()
|
||||
{
|
||||
var databaseType = _config.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey];
|
||||
var connectionString = NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey));
|
||||
var databaseType = _config.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey];
|
||||
|
||||
return new InstallationContext(databases.Single(d => d.Name == databaseType), connectionString);
|
||||
IDatabase database = null;
|
||||
if (!string.IsNullOrEmpty(databaseType))
|
||||
{
|
||||
var type = Type.GetType(databaseType);
|
||||
database = Activator.CreateInstance(type) as IDatabase;
|
||||
}
|
||||
|
||||
return new InstallationContext(database, connectionString);
|
||||
}
|
||||
|
||||
private string GetInstallationConfig(string key, string defaultValue)
|
||||
{
|
||||
var value = _config.GetSection(SettingKeys.InstallationSection).GetValue(key, defaultValue);
|
||||
// double fallback to default value - allow hold sample keys in config
|
||||
if (string.IsNullOrEmpty(value)) value = defaultValue;
|
||||
return value;
|
||||
return _configManager.GetSetting(SettingKeys.InstallationSection, key, defaultValue);
|
||||
}
|
||||
|
||||
private string NormalizeConnectionString(string connectionString)
|
||||
@ -614,46 +662,47 @@ namespace Oqtane.Infrastructure
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
private void SetValueRecursively<T>(string sectionPathKey, dynamic jsonObj, T value)
|
||||
{
|
||||
// split the string at the first ':' character
|
||||
var remainingSections = sectionPathKey.Split(":", 2);
|
||||
|
||||
var currentSection = remainingSections[0];
|
||||
if (remainingSections.Length > 1)
|
||||
{
|
||||
// continue with the process, moving down the tree
|
||||
var nextSection = remainingSections[1];
|
||||
SetValueRecursively(nextSection, jsonObj[currentSection], value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we've got to the end of the tree, set the value
|
||||
jsonObj[currentSection] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateConnectionString(string connectionString)
|
||||
{
|
||||
connectionString = DenormalizeConnectionString(connectionString);
|
||||
if (_config.GetConnectionString(SettingKeys.ConnectionStringKey) != connectionString)
|
||||
{
|
||||
AddOrUpdateAppSetting($"{SettingKeys.ConnectionStringsSection}:{SettingKeys.ConnectionStringKey}", connectionString);
|
||||
_config.Reload();
|
||||
_configManager.AddOrUpdateSetting($"{SettingKeys.ConnectionStringsSection}:{SettingKeys.ConnectionStringKey}", connectionString, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateDatabaseType(string databaseType)
|
||||
{
|
||||
AddOrUpdateAppSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", databaseType);
|
||||
_config.Reload();
|
||||
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", databaseType, true);
|
||||
}
|
||||
|
||||
public void UpgradeSqlServer(ISqlRepository sql, string connectionString, bool isMaster)
|
||||
public void UpgradeSqlServer(ISqlRepository sql, string connectionString, string databaseType, bool isMaster)
|
||||
{
|
||||
var script = (isMaster) ? "MigrateMaster.sql" : "MigrateTenant.sql";
|
||||
|
||||
sql.ExecuteScript(connectionString, Assembly.GetExecutingAssembly(), script);
|
||||
var query = sql.GetScriptFromAssembly(Assembly.GetExecutingAssembly(), script);
|
||||
query = query.Replace("{{Version}}", Constants.Version);
|
||||
|
||||
sql.ExecuteNonQuery(connectionString, databaseType, query);
|
||||
}
|
||||
|
||||
private void ValidateConfiguration()
|
||||
{
|
||||
if (_configManager.GetSetting(SettingKeys.DatabaseSection, SettingKeys.DatabaseTypeKey, "") == "")
|
||||
{
|
||||
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", Constants.DefaultDBType, true);
|
||||
}
|
||||
if (!_configManager.GetSection(SettingKeys.AvailableDatabasesSection).Exists())
|
||||
{
|
||||
string databases = "[";
|
||||
databases += "{ \"Name\": \"LocalDB\", \"ControlType\": \"Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
|
||||
databases += "{ \"Name\": \"SQL Server\", \"ControlType\": \"Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
|
||||
databases += "{ \"Name\": \"SQLite\", \"ControlType\": \"Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Database.Sqlite\" },";
|
||||
databases += "{ \"Name\": \"MySQL\", \"ControlType\": \"Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.MySQL.SqlServerDatabase, Oqtane.Database.MySQL\" },";
|
||||
databases += "{ \"Name\": \"PostgreSQL\", \"ControlType\": \"Oqtane.Installer.Controls.PostgreSQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Database.PostgreSQL\" }";
|
||||
databases += "]";
|
||||
_configManager.AddOrUpdateSetting(SettingKeys.AvailableDatabasesSection, JsonConvert.DeserializeObject<dynamic>(databases), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Oqtane.Shared;
|
||||
// ReSharper disable AssignNullToNotNullAttribute
|
||||
@ -18,170 +20,228 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
private readonly IHostApplicationLifetime _hostApplicationLifetime;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly IMemoryCache _cache;
|
||||
|
||||
public InstallationManager(IHostApplicationLifetime hostApplicationLifetime, IWebHostEnvironment environment, IMemoryCache cache)
|
||||
public InstallationManager(IHostApplicationLifetime hostApplicationLifetime, IWebHostEnvironment environment)
|
||||
{
|
||||
_hostApplicationLifetime = hostApplicationLifetime;
|
||||
_environment = environment;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
public void InstallPackages(string folders)
|
||||
public void InstallPackages()
|
||||
{
|
||||
if (!InstallPackages(folders, _environment.WebRootPath, _environment.ContentRootPath))
|
||||
if (!InstallPackages(_environment.WebRootPath, _environment.ContentRootPath))
|
||||
{
|
||||
// error installing packages
|
||||
}
|
||||
}
|
||||
|
||||
public static bool InstallPackages(string folders, string webRootPath, string contentRootPath)
|
||||
public static bool InstallPackages(string webRootPath, string contentRootPath)
|
||||
{
|
||||
bool install = false;
|
||||
string binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
string binPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
|
||||
foreach (string folder in folders.Split(','))
|
||||
string sourceFolder = Path.Combine(contentRootPath, "Packages");
|
||||
if (!Directory.Exists(sourceFolder))
|
||||
{
|
||||
string sourceFolder = Path.Combine(webRootPath, folder);
|
||||
if (!Directory.Exists(sourceFolder))
|
||||
{
|
||||
Directory.CreateDirectory(sourceFolder);
|
||||
}
|
||||
Directory.CreateDirectory(sourceFolder);
|
||||
}
|
||||
|
||||
// iterate through Nuget packages in source folder
|
||||
foreach (string packagename in Directory.GetFiles(sourceFolder, "*.nupkg"))
|
||||
// move packages to secure /Packages folder
|
||||
foreach (var folder in "Modules,Themes,Packages".Split(","))
|
||||
{
|
||||
foreach(var file in Directory.GetFiles(Path.Combine(webRootPath, folder), "*.nupkg*"))
|
||||
{
|
||||
// iterate through files
|
||||
using (ZipArchive archive = ZipFile.OpenRead(packagename))
|
||||
var destinationFile = Path.Combine(sourceFolder, Path.GetFileName(file));
|
||||
if (File.Exists(destinationFile))
|
||||
{
|
||||
string frameworkversion = "";
|
||||
// locate nuspec
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
File.Delete(destinationFile);
|
||||
}
|
||||
if (destinationFile.ToLower().EndsWith(".nupkg.bak"))
|
||||
{
|
||||
// leave a copy in the current folder as it is distributed with the core framework
|
||||
File.Copy(file, destinationFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// move to destination
|
||||
File.Move(file, destinationFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// iterate through Nuget packages in source folder
|
||||
foreach (string packagename in Directory.GetFiles(sourceFolder, "*.nupkg"))
|
||||
{
|
||||
// iterate through files
|
||||
using (ZipArchive archive = ZipFile.OpenRead(packagename))
|
||||
{
|
||||
string frameworkversion = "";
|
||||
// locate nuspec
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
if (entry.FullName.ToLower().EndsWith(".nuspec"))
|
||||
{
|
||||
if (entry.FullName.ToLower().EndsWith(".nuspec"))
|
||||
// open nuspec
|
||||
XmlTextReader reader = new XmlTextReader(entry.Open());
|
||||
reader.Namespaces = false; // remove namespace
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(reader);
|
||||
// get framework dependency
|
||||
XmlNode node = doc.SelectSingleNode("/package/metadata/dependencies/dependency[@id='Oqtane.Framework']");
|
||||
if (node != null)
|
||||
{
|
||||
// open nuspec
|
||||
XmlTextReader reader = new XmlTextReader(entry.Open());
|
||||
reader.Namespaces = false; // remove namespace
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(reader);
|
||||
// get framework dependency
|
||||
XmlNode node = doc.SelectSingleNode("/package/metadata/dependencies/dependency[@id='Oqtane.Framework']");
|
||||
if (node != null)
|
||||
{
|
||||
frameworkversion = node.Attributes["version"].Value;
|
||||
}
|
||||
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
|
||||
// if compatible with framework version
|
||||
if (frameworkversion == "" || Version.Parse(Constants.Version).CompareTo(Version.Parse(frameworkversion)) >= 0)
|
||||
{
|
||||
List<string> assets = new List<string>();
|
||||
bool manifest = false;
|
||||
|
||||
// module and theme packages must be in form of name.1.0.0.nupkg
|
||||
string name = Path.GetFileNameWithoutExtension(packagename);
|
||||
string[] segments = name?.Split('.');
|
||||
if (segments != null) name = string.Join('.', segments, 0, segments.Length - 3);
|
||||
|
||||
// deploy to appropriate locations
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
string foldername = Path.GetDirectoryName(entry.FullName).Split(Path.DirectorySeparatorChar)[0];
|
||||
string filename = Path.GetFileName(entry.FullName);
|
||||
|
||||
if (!manifest && filename == "assets.json")
|
||||
{
|
||||
manifest = true;
|
||||
}
|
||||
|
||||
switch (foldername)
|
||||
{
|
||||
case "lib":
|
||||
filename = Path.Combine(binFolder, filename);
|
||||
ExtractFile(entry, filename);
|
||||
assets.Add(filename.Replace(contentRootPath, ""));
|
||||
break;
|
||||
case "wwwroot":
|
||||
filename = Path.Combine(webRootPath, Utilities.PathCombine(entry.FullName.Replace("wwwroot/", "").Split('/')));
|
||||
ExtractFile(entry, filename);
|
||||
assets.Add(filename.Replace(contentRootPath, ""));
|
||||
break;
|
||||
case "runtimes":
|
||||
var destSubFolder = Path.GetDirectoryName(entry.FullName);
|
||||
filename = Path.Combine(binFolder, destSubFolder, filename);
|
||||
ExtractFile(entry, filename);
|
||||
assets.Add(filename.Replace(contentRootPath, ""));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// save dynamic list of assets
|
||||
if (!manifest && assets.Count != 0)
|
||||
{
|
||||
string manifestpath = Path.Combine(webRootPath, folder, name, "assets.json");
|
||||
if (File.Exists(manifestpath))
|
||||
{
|
||||
File.Delete(manifestpath);
|
||||
}
|
||||
if (!Directory.Exists(Path.GetDirectoryName(manifestpath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(manifestpath));
|
||||
}
|
||||
File.WriteAllText(manifestpath, JsonSerializer.Serialize(assets));
|
||||
frameworkversion = node.Attributes["version"].Value;
|
||||
}
|
||||
reader.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// remove package
|
||||
File.Delete(packagename);
|
||||
install = true;
|
||||
// if compatible with framework version
|
||||
if (frameworkversion == "" || Version.Parse(Constants.Version).CompareTo(Version.Parse(frameworkversion)) >= 0)
|
||||
{
|
||||
List<string> assets = new List<string>();
|
||||
bool manifest = false;
|
||||
string name = Path.GetFileNameWithoutExtension(packagename);
|
||||
|
||||
// deploy to appropriate locations
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
string filename = "";
|
||||
|
||||
// evaluate entry root folder
|
||||
switch (entry.FullName.Split('/')[0])
|
||||
{
|
||||
case "lib": // lib/net5.0/...
|
||||
filename = ExtractFile(entry, binPath, 2);
|
||||
break;
|
||||
case "wwwroot": // wwwroot/...
|
||||
filename = ExtractFile(entry, webRootPath, 1);
|
||||
break;
|
||||
case "runtimes": // runtimes/name/...
|
||||
filename = ExtractFile(entry, binPath, 0);
|
||||
break;
|
||||
case "ref": // ref/net5.0/...
|
||||
filename = ExtractFile(entry, Path.Combine(binPath, "ref"), 2);
|
||||
break;
|
||||
}
|
||||
|
||||
if (filename != "")
|
||||
{
|
||||
// ContentRootPath sometimes produces inconsistent path casing - so can't use string.Replace()
|
||||
filename = Regex.Replace(filename, Regex.Escape(contentRootPath), "", RegexOptions.IgnoreCase);
|
||||
assets.Add(filename);
|
||||
if (!manifest && Path.GetExtension(filename) == ".log")
|
||||
{
|
||||
manifest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save dynamic list of assets
|
||||
if (!manifest && assets.Count != 0)
|
||||
{
|
||||
string manifestpath = Path.Combine(sourceFolder, name + ".log");
|
||||
if (File.Exists(manifestpath))
|
||||
{
|
||||
File.Delete(manifestpath);
|
||||
}
|
||||
if (!Directory.Exists(Path.GetDirectoryName(manifestpath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(manifestpath));
|
||||
}
|
||||
File.WriteAllText(manifestpath, JsonSerializer.Serialize(assets, new JsonSerializerOptions { WriteIndented = true }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove package
|
||||
File.Delete(packagename);
|
||||
install = true;
|
||||
}
|
||||
|
||||
return install;
|
||||
}
|
||||
|
||||
private static void ExtractFile(ZipArchiveEntry entry, string filename)
|
||||
private static string ExtractFile(ZipArchiveEntry entry, string folder, int ignoreLeadingSegments)
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(filename)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||
}
|
||||
string[] segments = entry.FullName.Split('/'); // ZipArchiveEntries always use unix path separator
|
||||
string filename = Path.Combine(folder, string.Join(Path.DirectorySeparatorChar, segments, ignoreLeadingSegments, segments.Length - ignoreLeadingSegments));
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(filename)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||
}
|
||||
entry.ExtractToFile(filename, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// an error occurred extracting the file
|
||||
filename = "";
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
public bool UninstallPackage(string PackageName)
|
||||
{
|
||||
// get manifest with highest version
|
||||
string packagename = "";
|
||||
string[] packages = Directory.GetFiles(Path.Combine(_environment.ContentRootPath, "Packages"), PackageName + "*.log");
|
||||
if (packages.Length > 0)
|
||||
{
|
||||
packagename = packages[packages.Length - 1]; // use highest version
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(packagename))
|
||||
{
|
||||
// use manifest to clean up file resources
|
||||
List<string> assets = JsonSerializer.Deserialize<List<string>>(File.ReadAllText(packagename));
|
||||
assets.Reverse();
|
||||
foreach (string asset in assets)
|
||||
{
|
||||
// legacy support for assets that were stored as absolute paths
|
||||
string filepath = asset.StartsWith("\\") ? Path.Combine(_environment.ContentRootPath, asset.Substring(1)) : asset;
|
||||
if (File.Exists(filepath))
|
||||
{
|
||||
File.Delete(filepath);
|
||||
if (!Directory.EnumerateFiles(Path.GetDirectoryName(filepath)).Any())
|
||||
{
|
||||
Directory.Delete(Path.GetDirectoryName(filepath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clean up package asset manifests
|
||||
foreach(string asset in packages)
|
||||
{
|
||||
File.Delete(asset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void UpgradeFramework()
|
||||
{
|
||||
string folder = Path.Combine(_environment.WebRootPath, "Framework");
|
||||
string folder = Path.Combine(_environment.ContentRootPath, "Packages");
|
||||
if (Directory.Exists(folder))
|
||||
{
|
||||
// get package with highest version and clean up any others
|
||||
// get package with highest version
|
||||
string packagename = "";
|
||||
foreach (string package in Directory.GetFiles(folder, "Oqtane.Framework.*.nupkg"))
|
||||
string[] packages = Directory.GetFiles(folder, Constants.PackageId + ".*.nupkg");
|
||||
if (packages.Length > 0)
|
||||
{
|
||||
if (packagename != "")
|
||||
{
|
||||
File.Delete(packagename);
|
||||
}
|
||||
packagename = package;
|
||||
packagename = packages[packages.Length - 1]; // use highest version
|
||||
}
|
||||
|
||||
if (packagename != "")
|
||||
{
|
||||
// verify package version
|
||||
string packageversion = "";
|
||||
string packageurl = "";
|
||||
using (ZipArchive archive = ZipFile.OpenRead(packagename))
|
||||
{
|
||||
// locate nuspec
|
||||
@ -200,6 +260,11 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
packageversion = node.InnerText;
|
||||
}
|
||||
node = doc.SelectSingleNode("/package/metadata/projectUrl");
|
||||
if (node != null)
|
||||
{
|
||||
packageurl = node.InnerText;
|
||||
}
|
||||
reader.Close();
|
||||
break;
|
||||
}
|
||||
@ -207,9 +272,20 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
|
||||
// ensure package version is greater than or equal to current framework version
|
||||
if (packageversion != "" && Version.Parse(Constants.Version).CompareTo(Version.Parse(packageversion)) <= 0)
|
||||
if (packageversion != "" && Version.Parse(Constants.Version).CompareTo(Version.Parse(packageversion)) <= 0 && packageurl != "")
|
||||
{
|
||||
FinishUpgrade();
|
||||
// install Oqtane.Framework and Oqtane.Updater nuget packages
|
||||
InstallPackages();
|
||||
// download upgrade zip package
|
||||
var client = new WebClient();
|
||||
Uri uri = new Uri(packageurl);
|
||||
string upgradepackage = Path.Combine(folder, uri.Segments[uri.Segments.Length - 1]);
|
||||
client.DownloadFile(packageurl, upgradepackage);
|
||||
// install Oqtane.Upgrade zip package
|
||||
if (File.Exists(upgradepackage))
|
||||
{
|
||||
FinishUpgrade();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -217,19 +293,19 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
private void FinishUpgrade()
|
||||
{
|
||||
// check if upgrade application exists
|
||||
string Upgrader = "Oqtane.Upgrade.dll";
|
||||
// check if updater application exists
|
||||
string Updater = Constants.UpdaterPackageId + ".dll";
|
||||
string folder = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
if (folder == null || !File.Exists(Path.Combine(folder, Upgrader))) return;
|
||||
if (folder == null || !File.Exists(Path.Combine(folder, Updater))) return;
|
||||
|
||||
// run upgrade application
|
||||
// run updater application
|
||||
using (var process = new Process())
|
||||
{
|
||||
process.StartInfo = new ProcessStartInfo
|
||||
{
|
||||
WorkingDirectory = folder,
|
||||
FileName = "dotnet",
|
||||
Arguments = Path.Combine(folder, Upgrader) + " \"" + _environment.ContentRootPath + "\" \"" + _environment.WebRootPath + "\"",
|
||||
Arguments = Path.Combine(folder, Updater) + " \"" + _environment.ContentRootPath + "\" \"" + _environment.WebRootPath + "\"",
|
||||
UseShellExecute = false,
|
||||
ErrorDialog = false,
|
||||
CreateNoWindow = true,
|
||||
|
16
Oqtane.Server/Infrastructure/Interfaces/IConfigManager.cs
Normal file
16
Oqtane.Server/Infrastructure/Interfaces/IConfigManager.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public interface IConfigManager
|
||||
{
|
||||
public IConfigurationSection GetSection(string sectionKey);
|
||||
public T GetSetting<T>(string settingKey, T defaultValue);
|
||||
public T GetSetting<T>(string sectionKey, string settingKey, T defaultValue);
|
||||
void AddOrUpdateSetting<T>(string key, T value, bool reload);
|
||||
void AddOrUpdateSetting<T>(string file, string key, T value, bool reload);
|
||||
void RemoveSetting(string key, bool reload);
|
||||
void RemoveSetting(string file, string key, bool reload);
|
||||
void Reload();
|
||||
}
|
||||
}
|
@ -2,7 +2,8 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
public interface IInstallationManager
|
||||
{
|
||||
void InstallPackages(string folders);
|
||||
void InstallPackages();
|
||||
bool UninstallPackage(string PackageName);
|
||||
void UpgradeFramework();
|
||||
void RestartApplication();
|
||||
}
|
||||
|
12
Oqtane.Server/Infrastructure/Interfaces/ITenantManager.cs
Normal file
12
Oqtane.Server/Infrastructure/Interfaces/ITenantManager.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public interface ITenantManager
|
||||
{
|
||||
Alias GetAlias();
|
||||
Tenant GetTenant();
|
||||
void SetAlias(Alias alias);
|
||||
void SetTenant(int tenantId);
|
||||
}
|
||||
}
|
@ -92,11 +92,12 @@ namespace Oqtane.Infrastructure
|
||||
try
|
||||
{
|
||||
var notes = "";
|
||||
var tenants = scope.ServiceProvider.GetRequiredService<ITenantRepository>();
|
||||
var siteState = scope.ServiceProvider.GetRequiredService<SiteState>();
|
||||
foreach (var tenant in tenants.GetTenants())
|
||||
var tenantRepository = scope.ServiceProvider.GetRequiredService<ITenantRepository>();
|
||||
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
foreach (var tenant in tenantRepository.GetTenants())
|
||||
{
|
||||
siteState.Alias = new Alias { TenantId = tenant.TenantId };
|
||||
// set tenant and execute job
|
||||
tenantManager.SetTenant(tenant.TenantId);
|
||||
notes += ExecuteJob(scope.ServiceProvider);
|
||||
}
|
||||
log.Notes = notes;
|
||||
|
@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Oqtane.Shared;
|
||||
@ -9,7 +11,7 @@ namespace Oqtane.Infrastructure
|
||||
public class LocalizationManager : ILocalizationManager
|
||||
{
|
||||
private static readonly string DefaultCulture = Constants.DefaultCulture;
|
||||
private static readonly string[] SupportedCultures = new[] { DefaultCulture };
|
||||
private static readonly string[] DefaultSupportedCultures = new[] { DefaultCulture };
|
||||
|
||||
private readonly LocalizationOptions _localizationOptions;
|
||||
|
||||
@ -19,25 +21,19 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
|
||||
public string GetDefaultCulture()
|
||||
=> string.IsNullOrEmpty(_localizationOptions.DefaultCulture)
|
||||
=> String.IsNullOrEmpty(_localizationOptions.DefaultCulture)
|
||||
? DefaultCulture
|
||||
: _localizationOptions.DefaultCulture;
|
||||
|
||||
public string[] GetSupportedCultures()
|
||||
{
|
||||
List<string> cultures = new List<string>();
|
||||
var cultures = new List<string>(DefaultSupportedCultures);
|
||||
foreach(var file in Directory.EnumerateFiles(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Oqtane.Client.resources.dll", SearchOption.AllDirectories))
|
||||
{
|
||||
cultures.Add(Path.GetFileName(Path.GetDirectoryName(file)));
|
||||
}
|
||||
if (cultures.Count == 0)
|
||||
{
|
||||
return SupportedCultures;
|
||||
}
|
||||
else
|
||||
{
|
||||
return cultures.ToArray();
|
||||
}
|
||||
|
||||
return cultures.OrderBy(c => c).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,18 +14,18 @@ namespace Oqtane.Infrastructure
|
||||
public class LogManager : ILogManager
|
||||
{
|
||||
private readonly ILogRepository _logs;
|
||||
private readonly ITenantResolver _tenantResolver;
|
||||
private readonly IConfigurationRoot _config;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public LogManager(ILogRepository logs, ITenantResolver tenantResolver, IConfigurationRoot config, IUserPermissions userPermissions, IHttpContextAccessor accessor)
|
||||
public LogManager(ILogRepository logs, ITenantManager tenantManager, IConfigurationRoot config, IUserPermissions userPermissions, IHttpContextAccessor accessor)
|
||||
{
|
||||
_logs = logs;
|
||||
_tenantResolver = tenantResolver;
|
||||
_config = config;
|
||||
_userPermissions = userPermissions;
|
||||
_accessor = accessor;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
public void Log(LogLevel level, object @class, LogFunction function, string message, params object[] args)
|
||||
@ -49,10 +49,9 @@ namespace Oqtane.Infrastructure
|
||||
if (siteId == -1)
|
||||
{
|
||||
log.SiteId = null;
|
||||
Alias alias = _tenantResolver.GetAlias();
|
||||
if (alias != null)
|
||||
if (_alias != null)
|
||||
{
|
||||
log.SiteId = alias.SiteId;
|
||||
log.SiteId = _alias.SiteId;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
41
Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs
Normal file
41
Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
internal class TenantMiddleware
|
||||
{
|
||||
private readonly RequestDelegate next;
|
||||
|
||||
public TenantMiddleware(RequestDelegate next)
|
||||
{
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
// check if framework is installed
|
||||
var config = context.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration;
|
||||
if (!string.IsNullOrEmpty(config.GetConnectionString("DefaultConnection")))
|
||||
{
|
||||
// get alias
|
||||
var tenantManager = context.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager;
|
||||
var alias = tenantManager.GetAlias();
|
||||
|
||||
// rewrite path by removing alias path prefix from api and pages requests
|
||||
if (alias != null && !string.IsNullOrEmpty(alias.Path))
|
||||
{
|
||||
string path = context.Request.Path.ToString();
|
||||
if (path.StartsWith("/" + alias.Path) && (path.Contains("/api/") || path.Contains("/pages/")))
|
||||
{
|
||||
context.Request.Path = path.Replace("/" + alias.Path, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// continue processing
|
||||
if (next != null) await next(context);
|
||||
}
|
||||
}
|
||||
}
|
@ -54,10 +54,10 @@ namespace Oqtane.SiteTemplates
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
}.EncodePermissions(),
|
||||
Content = "<p><a href=\"https://www.oqtane.org\" target=\"_new\">Oqtane</a> is an open source <b>modular application framework</b> that provides advanced functionality for developing web and mobile applications on ASP.NET Core. It leverages the revolutionary new Blazor component model to compose a <b>fully dynamic</b> web development experience which can be hosted either client-side or server-side. Whether you are looking for a platform to <b>accelerate your web development</b> efforts, or simply interested in exploring the anatomy of a large-scale Blazor application, Oqtane provides a solid foundation based on proven enterprise architectural principles.</p>" +
|
||||
Content = "<p><a href=\"https://www.oqtane.org\" target=\"_new\">Oqtane</a> is an open source <b>modular application framework</b> that provides advanced functionality for developing web and mobile applications on .NET Core. It leverages the Blazor component model to compose a <b>fully dynamic</b> web development experience which can be hosted either client-side or server-side. Whether you are looking for a platform to <b>accelerate your web development</b> efforts, or simply interested in exploring the anatomy of a large-scale Blazor application, Oqtane provides a solid foundation based on proven enterprise architectural principles.</p>" +
|
||||
"<p align=\"center\"><a href=\"https://www.oqtane.org\" target=\"_new\"><img class=\"img-fluid\" src=\"oqtane-glow.png\"></a></p><p align=\"center\"><a class=\"btn btn-primary\" href=\"https://www.oqtane.org/Community\" target=\"_new\">Join Our Community</a> <a class=\"btn btn-primary\" href=\"https://github.com/oqtane/oqtane.framework\" target=\"_new\">Clone Our Repo</a></p>" +
|
||||
"<p><a href=\"https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor\" target=\"_new\">Blazor</a> is an open source and cross-platform web UI framework for building single-page apps using .NET and C# instead of JavaScript. Blazor WebAssembly relies on Wasm, an open web standard that does not require plugins or code transpilation in order to run natively in a web browser. Blazor Server uses SignalR to host your application on a web server and provide a responsive and robust development experience. Blazor applications work in all modern web browsers, including mobile browsers.</p>" +
|
||||
"<p>Blazor is a feature of <a href=\"https://dotnet.microsoft.com/apps/aspnet\" target=\"_new\">ASP.NET Core 3</a>, the popular cross platform web development framework from Microsoft that extends the <a href=\"https://dotnet.microsoft.com/learn/dotnet/what-is-dotnet\" target=\"_new\" >.NET developer platform</a> with tools and libraries for building web apps.</p>"
|
||||
"<p>Blazor is a feature of <a href=\"https://dotnet.microsoft.com/apps/aspnet\" target=\"_new\">.NET Core</a>, the popular cross platform web development framework from Microsoft that extends the <a href=\"https://dotnet.microsoft.com/learn/dotnet/what-is-dotnet\" target=\"_new\" >.NET developer platform</a> with tools and libraries for building web apps.</p>"
|
||||
},
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "MIT License", Pane = "Content",
|
||||
ModulePermissions = new List<Permission> {
|
||||
|
87
Oqtane.Server/Infrastructure/TenantManager.cs
Normal file
87
Oqtane.Server/Infrastructure/TenantManager.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class TenantManager : ITenantManager
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IAliasRepository _aliasRepository;
|
||||
private readonly ITenantRepository _tenantRepository;
|
||||
private readonly SiteState _siteState;
|
||||
|
||||
public TenantManager(IHttpContextAccessor httpContextAccessor, IAliasRepository aliasRepository, ITenantRepository tenantRepository, SiteState siteState)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_aliasRepository = aliasRepository;
|
||||
_tenantRepository = tenantRepository;
|
||||
_siteState = siteState;
|
||||
}
|
||||
|
||||
public Alias GetAlias()
|
||||
{
|
||||
Alias alias = null;
|
||||
|
||||
if (_siteState != null && _siteState.Alias != null)
|
||||
{
|
||||
alias = _siteState.Alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if there is http context
|
||||
if (_httpContextAccessor.HttpContext != null)
|
||||
{
|
||||
// legacy support for client api requests which would include the alias as a path prefix ( ie. {alias}/api/[controller] )
|
||||
int aliasId;
|
||||
string[] segments = _httpContextAccessor.HttpContext.Request.Path.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (segments.Length > 1 && (segments[1] == "api" || segments[1] == "pages") && int.TryParse(segments[0], out aliasId))
|
||||
{
|
||||
alias = _aliasRepository.GetAliases().ToList().FirstOrDefault(item => item.AliasId == aliasId);
|
||||
}
|
||||
|
||||
// resolve alias based on host name and path
|
||||
if (alias == null)
|
||||
{
|
||||
string name = _httpContextAccessor.HttpContext.Request.Host.Value + _httpContextAccessor.HttpContext.Request.Path;
|
||||
alias = _aliasRepository.GetAlias(name);
|
||||
}
|
||||
|
||||
// if there is a match save it
|
||||
if (alias != null)
|
||||
{
|
||||
_siteState.Alias = alias;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alias;
|
||||
}
|
||||
|
||||
public Tenant GetTenant()
|
||||
{
|
||||
var alias = GetAlias();
|
||||
if (alias != null)
|
||||
{
|
||||
// return tenant details
|
||||
return _tenantRepository.GetTenants().ToList().FirstOrDefault(item => item.TenantId == alias.TenantId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SetAlias(Alias alias)
|
||||
{
|
||||
// background processes can set the alias using the SiteState service
|
||||
_siteState.Alias = alias;
|
||||
}
|
||||
|
||||
public void SetTenant(int tenantId)
|
||||
{
|
||||
// background processes can set the alias using the SiteState service
|
||||
_siteState.Alias = new Alias { TenantId = tenantId };
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
@ -11,15 +13,15 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class UpgradeManager : IUpgradeManager
|
||||
{
|
||||
private readonly IAliasRepository _aliases;
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly IConfigManager _configManager;
|
||||
|
||||
public UpgradeManager(IAliasRepository aliases, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment)
|
||||
public UpgradeManager(IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IConfigManager configManager)
|
||||
{
|
||||
_aliases = aliases;
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_environment = environment;
|
||||
_configManager = configManager;
|
||||
}
|
||||
|
||||
public void Upgrade(Tenant tenant, string version)
|
||||
@ -27,9 +29,9 @@ namespace Oqtane.Infrastructure
|
||||
// core framework upgrade logic - executed for every tenant
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
// set SiteState based on tenant
|
||||
var siteState = scope.ServiceProvider.GetRequiredService<SiteState>();
|
||||
siteState.Alias = new Alias { TenantId = tenant.TenantId };
|
||||
// set tenant
|
||||
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
tenantManager.SetTenant(tenant.TenantId);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
@ -39,6 +41,9 @@ namespace Oqtane.Infrastructure
|
||||
case "2.0.2":
|
||||
Upgrade_2_0_2(tenant, scope);
|
||||
break;
|
||||
case "2.1.0":
|
||||
Upgrade_2_1_0(tenant, scope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,6 +116,18 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
}
|
||||
|
||||
private void Upgrade_2_1_0(Tenant tenant, IServiceScope scope)
|
||||
{
|
||||
if (tenant.Name == TenantNames.Master)
|
||||
{
|
||||
_configManager.RemoveSetting("Localization:SupportedCultures", true);
|
||||
if (_configManager.GetSetting("RenderMode", "") == "")
|
||||
{
|
||||
_configManager.AddOrUpdateSetting("RenderMode", "ServerPrerendered", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateSitePages(IServiceScope scope, List<PageTemplate> pageTemplates)
|
||||
{
|
||||
if (pageTemplates.Count != 0)
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<AliasEntityBuilder> _primaryKey = new("PK_Alias", x => x.AliasId);
|
||||
private readonly ForeignKey<AliasEntityBuilder> _tenantForeignKey = new("FK_Alias_Tenant", x => x.TenantId, "Tenant", "TenantId", ReferentialAction.Cascade);
|
||||
|
||||
public AliasEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public AliasEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
namespace Oqtane.Migrations.EntityBuilders
|
||||
@ -10,7 +11,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private const string _entityTableName = "AppVersions";
|
||||
private readonly PrimaryKey<AppVersionsEntityBuilder> _primaryKey = new("PK_AppVersions", x => x.Id);
|
||||
|
||||
public AppVersionsEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public AppVersionsEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<AspNetUserClaimsEntityBuilder> _primaryKey = new("PK_AspNetUserClaims", x => x.Id);
|
||||
private readonly ForeignKey<AspNetUserClaimsEntityBuilder> _aspNetUsersForeignKey = new("FK_AspNetUserClaims_AspNetUsers_UserId", x => x.UserId, "AspNetUsers", "Id", ReferentialAction.Cascade);
|
||||
|
||||
public AspNetUserClaimsEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public AspNetUserClaimsEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private const string _entityTableName = "AspNetUsers";
|
||||
private readonly PrimaryKey<AspNetUsersEntityBuilder> _primaryKey = new("PK_AspNetUsers", x => x.Id);
|
||||
|
||||
public AspNetUsersEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public AspNetUsersEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
@ -10,7 +11,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
public abstract class AuditableBaseEntityBuilder<TEntityBuilder> : BaseEntityBuilder<TEntityBuilder> where TEntityBuilder : BaseEntityBuilder<TEntityBuilder>
|
||||
{
|
||||
protected AuditableBaseEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base (migrationBuilder, database)
|
||||
protected AuditableBaseEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base (migrationBuilder, database)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
|
||||
|
||||
@ -13,14 +14,14 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
private readonly MigrationBuilder _migrationBuilder;
|
||||
|
||||
protected BaseEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database)
|
||||
protected BaseEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database)
|
||||
{
|
||||
_migrationBuilder = migrationBuilder;
|
||||
ActiveDatabase = database;
|
||||
ForeignKeys = new List<ForeignKey<TEntityBuilder>>();
|
||||
}
|
||||
|
||||
protected IOqtaneDatabase ActiveDatabase { get; }
|
||||
protected IDatabase ActiveDatabase { get; }
|
||||
|
||||
protected abstract TEntityBuilder BuildTable(ColumnsBuilder table);
|
||||
|
||||
@ -182,6 +183,19 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
onDelete: foreignKey.OnDeleteAction);
|
||||
}
|
||||
|
||||
public void AddForeignKey(string name)
|
||||
{
|
||||
var foreignKey = ForeignKeys.Single(k => k.Name == name);
|
||||
|
||||
_migrationBuilder.AddForeignKey(
|
||||
name: RewriteName(foreignKey.Name),
|
||||
table: RewriteName(EntityTableName),
|
||||
column: RewriteName(foreignKey.ColumnName),
|
||||
principalTable: RewriteName(foreignKey.PrincipalTable),
|
||||
principalColumn: RewriteName(foreignKey.PrincipalColumn),
|
||||
onDelete: foreignKey.OnDeleteAction);
|
||||
}
|
||||
|
||||
public void DropForeignKey(ForeignKey<TEntityBuilder> foreignKey)
|
||||
{
|
||||
DropForeignKey(RewriteName(foreignKey.Name));
|
||||
@ -217,7 +231,6 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
public void DeleteFromTable(string condition = "")
|
||||
{
|
||||
var deleteSql = $"DELETE FROM {RewriteName(EntityTableName)} ";
|
||||
|
||||
if(!string.IsNullOrEmpty(condition))
|
||||
{
|
||||
deleteSql += $"WHERE {condition}";
|
||||
@ -227,11 +240,8 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
|
||||
public void UpdateColumn(string columnName, string value, string condition = "")
|
||||
{
|
||||
var updateValue = value;
|
||||
|
||||
var updateSql = $"UPDATE {RewriteName(EntityTableName)} SET {RewriteName(columnName)} = {value} ";
|
||||
|
||||
if(!string.IsNullOrEmpty(condition))
|
||||
if (!string.IsNullOrEmpty(condition))
|
||||
{
|
||||
updateSql += $"WHERE {condition}";
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
@ -10,7 +11,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
public abstract class DeletableAuditableBaseEntityBuilder<TEntityBuilder> : AuditableBaseEntityBuilder<TEntityBuilder> where TEntityBuilder : BaseEntityBuilder<TEntityBuilder>
|
||||
{
|
||||
protected DeletableAuditableBaseEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
protected DeletableAuditableBaseEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
@ -10,7 +11,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
public abstract class DeletableBaseEntityBuilder<TEntityBuilder> : BaseEntityBuilder<TEntityBuilder> where TEntityBuilder : BaseEntityBuilder<TEntityBuilder>
|
||||
{
|
||||
protected DeletableBaseEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
protected DeletableBaseEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<FileEntityBuilder> _primaryKey = new("PK_File", x => x.FileId);
|
||||
private readonly ForeignKey<FileEntityBuilder> _folderForeignKey = new("FK_File_Folder", x => x.FolderId, "Folder", "FolderId", ReferentialAction.Cascade);
|
||||
|
||||
public FileEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public FileEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<FolderEntityBuilder> _primaryKey = new("PK_Folder", x => x.FolderId);
|
||||
private readonly ForeignKey<FolderEntityBuilder> _siteForeignKey = new("FK_Folder_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||
|
||||
public FolderEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public FolderEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private const string _entityTableName = "Job";
|
||||
private readonly PrimaryKey<JobEntityBuilder> _primaryKey = new("PK_Job", x => x.JobId);
|
||||
|
||||
public JobEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public JobEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<JobLogEntityBuilder> _primaryKey = new("PK_JobLog", x => x.JobLogId);
|
||||
private readonly ForeignKey<JobLogEntityBuilder> _jobLogForeignKey = new("FK_JobLog_Job", x => x.JobId, "Job", "JobId", ReferentialAction.Cascade);
|
||||
|
||||
public JobLogEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public JobLogEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<LanguageEntityBuilder> _primaryKey = new("PK_Language", x => x.LanguageId);
|
||||
private readonly ForeignKey<LanguageEntityBuilder> _siteForeignKey = new("FK_Language_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||
|
||||
public LanguageEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public LanguageEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<LogEntityBuilder> _primaryKey = new("PK_Log", x => x.LogId);
|
||||
private readonly ForeignKey<LogEntityBuilder> _siteForeignKey = new("FK_Log_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||
|
||||
public LogEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public LogEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private const string _entityTableName = "ModuleDefinition";
|
||||
private readonly PrimaryKey<ModuleDefinitionsEntityBuilder> _primaryKey = new("PK_ModuleDefinition", x => x.ModuleDefinitionId);
|
||||
|
||||
public ModuleDefinitionsEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public ModuleDefinitionsEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<ModuleEntityBuilder> _primaryKey = new("PK_Module", x => x.ModuleId);
|
||||
private readonly ForeignKey<ModuleEntityBuilder> _siteForeignKey = new("FK_Module_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||
|
||||
public ModuleEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public ModuleEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<NotificationEntityBuilder> _primaryKey = new("PK_Notification", x => x.NotificationId);
|
||||
private readonly ForeignKey<NotificationEntityBuilder> _siteForeignKey = new("FK_Notification_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||
|
||||
public NotificationEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public NotificationEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<PageEntityBuilder> _primaryKey = new("PK_Page", x => x.PageId);
|
||||
private readonly ForeignKey<PageEntityBuilder> _siteForeignKey = new("FK_Page_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||
|
||||
public PageEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public PageEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
@ -25,7 +26,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
PageId = AddAutoIncrementColumn(table,"PageId");
|
||||
SiteId = AddIntegerColumn(table,"SiteId");
|
||||
if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB")
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
Path = AddStringColumn(table,"Path", 50);
|
||||
}
|
||||
@ -41,7 +42,6 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
Order = AddIntegerColumn(table,"Order");
|
||||
IsNavigation = AddBooleanColumn(table,"IsNavigation");
|
||||
Url = AddStringColumn(table,"Url", 500, true);
|
||||
LayoutType = AddStringColumn(table,"LayoutType", 200);
|
||||
UserId = AddIntegerColumn(table,"UserId", true);
|
||||
IsPersonalizable = AddBooleanColumn(table,"IsPersonalizable");
|
||||
DefaultContainerType = AddStringColumn(table,"DefaultContainerType", 200, true);
|
||||
@ -73,8 +73,6 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Url { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> LayoutType { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> UserId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> IsPersonalizable { get; private set; }
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -15,7 +16,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly ForeignKey<PageModuleEntityBuilder> _moduleForeignKey = new("FK_PageModule_Module", x => x.ModuleId, "Module", "ModuleId", ReferentialAction.NoAction);
|
||||
private readonly ForeignKey<PageModuleEntityBuilder> _pageForeignKey = new("FK_PageModule_Page", x => x.PageId, "Page", "PageId", ReferentialAction.Cascade);
|
||||
|
||||
public PageModuleEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public PageModuleEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -16,7 +17,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly ForeignKey<PermissionEntityBuilder> _userForeignKey = new("FK_Permission_User", x => x.UserId, "User", "UserId", ReferentialAction.NoAction);
|
||||
private readonly ForeignKey<PermissionEntityBuilder> _roleForeignKey = new("FK_Permission_Role", x => x.RoleId, "Role", "RoleId", ReferentialAction.NoAction);
|
||||
|
||||
public PermissionEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public PermissionEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<ProfileEntityBuilder> _primaryKey = new("PK_Profile", x => x.ProfileId);
|
||||
private readonly ForeignKey<ProfileEntityBuilder> _siteForeignKey = new("FK_Profile_Sites", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||
|
||||
public ProfileEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public ProfileEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -14,7 +15,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly PrimaryKey<RoleEntityBuilder> _primaryKey = new("PK_Role", x => x.RoleId);
|
||||
private readonly ForeignKey<RoleEntityBuilder> _siteForeignKey = new("FK_Role_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||
|
||||
public RoleEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public RoleEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private const string _entityTableName = "Setting";
|
||||
private readonly PrimaryKey<SettingEntityBuilder> _primaryKey = new("PK_Setting", x => x.SettingId);
|
||||
|
||||
public SettingEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public SettingEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
@ -24,7 +25,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
SettingId = AddAutoIncrementColumn(table,"SettingId");
|
||||
EntityName = AddStringColumn(table,"EntityName", 50);
|
||||
EntityId = AddIntegerColumn(table,"EntityId");
|
||||
SettingName = AddStringColumn(table,"SettingName", 50);
|
||||
SettingName = AddStringColumn(table,"SettingName", 200);
|
||||
SettingValue = AddMaxStringColumn(table,"SettingValue");
|
||||
|
||||
AddAuditableColumns(table);
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private const string _entityTableName = "Site";
|
||||
private readonly PrimaryKey<SiteEntityBuilder> _primaryKey = new("PK_Site", x => x.SiteId);
|
||||
|
||||
public SiteEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public SiteEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
@ -27,7 +28,6 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
LogoFileId = AddIntegerColumn(table,"LogoFileId", true);
|
||||
FaviconFileId = AddIntegerColumn(table,"FaviconFileId", true);
|
||||
DefaultThemeType = AddStringColumn(table,"DefaultThemeType", 200);
|
||||
DefaultLayoutType = AddStringColumn(table,"DefaultLayoutType", 200);
|
||||
DefaultContainerType = AddStringColumn(table,"DefaultContainerType", 200);
|
||||
PwaIsEnabled = AddBooleanColumn(table,"PwaIsEnabled");
|
||||
PwaAppIconFileId = AddIntegerColumn(table,"PwaAppIconFileId", true);
|
||||
@ -52,8 +52,6 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
|
||||
public OperationBuilder<AddColumnOperation> DefaultThemeType { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> DefaultLayoutType { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> DefaultContainerType { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> PwaIsEnabled { get; private set; }
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private const string _entityTableName = "Tenant";
|
||||
private readonly PrimaryKey<TenantEntityBuilder> _primaryKey = new("PK_Tenant", x => x.TenantId);
|
||||
|
||||
public TenantEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database): base(migrationBuilder, database)
|
||||
public TenantEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database): base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -13,7 +14,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private const string _entityTableName = "User";
|
||||
private readonly PrimaryKey<UserEntityBuilder> _primaryKey = new("PK_User", x => x.UserId);
|
||||
|
||||
public UserEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public UserEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -15,7 +16,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||
private readonly ForeignKey<UserRoleEntityBuilder> _userForeignKey = new("FK_UserRole_User", x => x.UserId, "User", "UserId", ReferentialAction.Cascade);
|
||||
private readonly ForeignKey<UserRoleEntityBuilder> _roleForeignKey = new("FK_UserRole_Role", x => x.RoleId, "Role", "RoleId", ReferentialAction.NoAction);
|
||||
|
||||
public UserRoleEntityBuilder(MigrationBuilder migrationBuilder, IOqtaneDatabase database) : base(migrationBuilder, database)
|
||||
public UserRoleEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
@ -20,6 +20,14 @@ namespace Oqtane.Migrations
|
||||
|
||||
public Expression<Func<TEntityBuilder, object>> Column { get;}
|
||||
|
||||
public string ColumnName
|
||||
{
|
||||
get
|
||||
{
|
||||
var body = Column.Body.ToString();
|
||||
return body.Substring(body.IndexOf(".") + 1);
|
||||
}
|
||||
}
|
||||
public ReferentialAction OnDeleteAction { get; }
|
||||
|
||||
public string PrincipalTable { get; }
|
||||
|
51
Oqtane.Server/Migrations/Framework/MigrationUtils.cs
Normal file
51
Oqtane.Server/Migrations/Framework/MigrationUtils.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Migrations.Framework
|
||||
{
|
||||
public static class MigrationUtils
|
||||
{
|
||||
public static string BuildInsertScript(HistoryRow row, HistoryRepositoryDependencies dependencies, MigrationHistoryTable historyTable )
|
||||
{
|
||||
var sqlGenerationHelper = dependencies.SqlGenerationHelper;
|
||||
var stringTypeMapping = dependencies.TypeMappingSource.GetMapping(typeof(string));
|
||||
|
||||
return new StringBuilder().Append("INSERT INTO ")
|
||||
.Append(sqlGenerationHelper.DelimitIdentifier(historyTable.TableName, historyTable.TableSchema))
|
||||
.Append(" (")
|
||||
.Append(sqlGenerationHelper.DelimitIdentifier(historyTable.MigrationIdColumnName))
|
||||
.Append(", ")
|
||||
.Append(sqlGenerationHelper.DelimitIdentifier(historyTable.ProductVersionColumnName))
|
||||
.Append(", ")
|
||||
.Append(sqlGenerationHelper.DelimitIdentifier(historyTable.AppliedVersionColumnName))
|
||||
.Append(", ")
|
||||
.Append(sqlGenerationHelper.DelimitIdentifier(historyTable.AppliedDateColumnName))
|
||||
.AppendLine(")")
|
||||
.Append("VALUES (")
|
||||
.Append(stringTypeMapping.GenerateSqlLiteral(row.MigrationId))
|
||||
.Append(", ")
|
||||
.Append(stringTypeMapping.GenerateSqlLiteral(row.ProductVersion))
|
||||
.Append(", ")
|
||||
.Append(stringTypeMapping.GenerateSqlLiteral(Constants.Version))
|
||||
.Append(", ")
|
||||
.Append(stringTypeMapping.GenerateSqlLiteral(DateTime.Now.ToString("yyyy'-'MM'-'dd' 'HH':'mm':'ss'.'fffffffK")))
|
||||
.Append(")")
|
||||
.AppendLine(sqlGenerationHelper.StatementTerminator)
|
||||
.ToString();
|
||||
}
|
||||
|
||||
// only used in upgrade scenarios for modules that used SQL scripts originally
|
||||
public static string BuildInsertScript(string MigrationId)
|
||||
{
|
||||
var query = "IF NOT EXISTS(SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = '" + MigrationId + "') ";
|
||||
query += "INSERT INTO __EFMigrationsHistory(MigrationId, ProductVersion, AppliedDate, AppliedVersion) ";
|
||||
query += "VALUES('" + MigrationId + "', '5.0.4', SYSDATETIME(), '" + Constants.Version + "')";
|
||||
return query;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,20 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
{
|
||||
public abstract class MultiDatabaseMigration : Migration
|
||||
{
|
||||
private readonly IEnumerable<IOqtaneDatabase> _databases;
|
||||
|
||||
protected MultiDatabaseMigration(IEnumerable<IOqtaneDatabase> databases)
|
||||
protected MultiDatabaseMigration(IDatabase database)
|
||||
{
|
||||
_databases = databases;
|
||||
ActiveDatabase = database;
|
||||
}
|
||||
|
||||
protected IOqtaneDatabase ActiveDatabase => _databases.FirstOrDefault(d => d.Provider == ActiveProvider);
|
||||
protected IDatabase ActiveDatabase { get; }
|
||||
|
||||
protected string RewriteName(string name)
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Internal;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Repository.Databases.Interfaces;
|
||||
|
||||
@ -13,7 +14,7 @@ namespace Oqtane.Migrations.Framework
|
||||
{
|
||||
public class MultiDatabaseMigrationsAssembly: MigrationsAssembly
|
||||
{
|
||||
private readonly IEnumerable<IOqtaneDatabase> _databases;
|
||||
private readonly IDatabase _database;
|
||||
|
||||
public MultiDatabaseMigrationsAssembly(
|
||||
ICurrentDbContext currentContext,
|
||||
@ -23,15 +24,15 @@ namespace Oqtane.Migrations.Framework
|
||||
: base(currentContext, options, idGenerator, logger)
|
||||
{
|
||||
var multiDatabaseContext = currentContext.Context as IMultiDatabase;
|
||||
if (multiDatabaseContext != null) _databases = multiDatabaseContext.Databases;
|
||||
if (multiDatabaseContext != null) _database = multiDatabaseContext.ActiveDatabase;
|
||||
}
|
||||
public override Migration CreateMigration(TypeInfo migrationClass, string activeProvider)
|
||||
{
|
||||
var hasCtorWithCacheOptions = migrationClass.GetConstructor(new[] { typeof(IEnumerable<IOqtaneDatabase>) }) != null;
|
||||
var hasCtorWithCacheOptions = migrationClass.GetConstructor(new[] { typeof(IDatabase) }) != null;
|
||||
|
||||
if (hasCtorWithCacheOptions)
|
||||
{
|
||||
var migration = (Migration)Activator.CreateInstance(migrationClass.AsType(), _databases);
|
||||
var migration = (Migration)Activator.CreateInstance(migrationClass.AsType(), _database);
|
||||
if (migration != null)
|
||||
{
|
||||
migration.ActiveProvider = activeProvider;
|
||||
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Master
|
||||
{
|
||||
[DbContext(typeof(MasterDBContext))]
|
||||
[Migration("Master.01.00.00.00")]
|
||||
public class InitializeMaster : MultiDatabaseMigration
|
||||
{
|
||||
public InitializeMaster(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public InitializeMaster(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Master
|
||||
{
|
||||
[DbContext(typeof(MasterDBContext))]
|
||||
[Migration("Master.01.00.01.00")]
|
||||
public class AddAdditionalIndexesInMaster : MultiDatabaseMigration
|
||||
{
|
||||
public AddAdditionalIndexesInMaster(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public AddAdditionalIndexesInMaster(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Master
|
||||
{
|
||||
[DbContext(typeof(MasterDBContext))]
|
||||
[Migration("Master.02.01.00.00")]
|
||||
public class AddIndexesForForeignKeyInMaster : MultiDatabaseMigration
|
||||
{
|
||||
public AddIndexesForForeignKeyInMaster(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public AddIndexesForForeignKeyInMaster(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Master
|
||||
{
|
||||
[DbContext(typeof(MasterDBContext))]
|
||||
[Migration("Master.02.01.00.01")]
|
||||
public class AddDatabaseTypeColumnToTenant : MultiDatabaseMigration
|
||||
{
|
||||
public AddDatabaseTypeColumnToTenant(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public AddDatabaseTypeColumnToTenant(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
@ -22,9 +21,9 @@ namespace Oqtane.Migrations
|
||||
tenantEntityBuilder.AddStringColumn("DBType", 200, true);
|
||||
|
||||
//Update new column if SqlServer (Other Databases will not have any records yet)
|
||||
if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB")
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
tenantEntityBuilder.UpdateColumn("DBType", "'SqlServer'");
|
||||
tenantEntityBuilder.UpdateColumn("DBType", $"'{ActiveDatabase.TypeName}'");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.01.00.00.00")]
|
||||
public class InitializeTenant : MultiDatabaseMigration
|
||||
{
|
||||
public InitializeTenant(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public InitializeTenant(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
@ -22,15 +20,22 @@ namespace Oqtane.Migrations
|
||||
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
siteEntityBuilder.Create();
|
||||
|
||||
//Add Column to Site table (for Sql Server only) we will drop it later for Sql Server only
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
siteEntityBuilder.AddStringColumn("DefaultLayoutType", 200, true);
|
||||
}
|
||||
|
||||
//Create Page table
|
||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
pageEntityBuilder.Create();
|
||||
pageEntityBuilder.AddIndex("IX_Page", new [] {"SiteId", "Path", "UserId"}, true);
|
||||
|
||||
//Add Column to Page table (for Sql Server only) we will drop it later for Sql Server only
|
||||
if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB")
|
||||
//Add Columns to Page table (for Sql Server only) we will drop them later for Sql Server only
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
pageEntityBuilder.AddBooleanColumn("EditMode");
|
||||
pageEntityBuilder.AddStringColumn("LayoutType", 200, true);
|
||||
}
|
||||
|
||||
//Create Module table
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.01.00.01.00")]
|
||||
public class AddAdditionalIndexesInTenant : MultiDatabaseMigration
|
||||
{
|
||||
public AddAdditionalIndexesInTenant(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public AddAdditionalIndexesInTenant(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.01.00.01.01")]
|
||||
public class AddAdditionColumnToNotifications : MultiDatabaseMigration
|
||||
{
|
||||
public AddAdditionColumnToNotifications(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public AddAdditionColumnToNotifications(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
@ -1,24 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.01.00.02.01")]
|
||||
public class DropColumnFromPage : MultiDatabaseMigration
|
||||
{
|
||||
public DropColumnFromPage(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public DropColumnFromPage(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
//Drop Column from Page table
|
||||
if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB")
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
pageEntityBuilder.DropColumn("EditMode");
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.02.00.00.01")]
|
||||
public class AddColumnToProfileAndUpdatePage : MultiDatabaseMigration
|
||||
{
|
||||
public AddColumnToProfileAndUpdatePage(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public AddColumnToProfileAndUpdatePage(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
@ -25,7 +24,7 @@ namespace Oqtane.Migrations
|
||||
profileEntityBuilder.UpdateColumn("Options", "''");
|
||||
|
||||
//Alter Column in Page table for Sql Server
|
||||
if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB")
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
pageEntityBuilder.DropIndex("IX_Page");
|
||||
@ -41,7 +40,7 @@ namespace Oqtane.Migrations
|
||||
profileEntityBuilder.DropColumn("Options");
|
||||
|
||||
//Alter Column in Page table
|
||||
if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB")
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
pageEntityBuilder.DropIndex("IX_Page");
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.02.00.01.01")]
|
||||
public class UpdateIconColumnInPage : MultiDatabaseMigration
|
||||
{
|
||||
public UpdateIconColumnInPage(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public UpdateIconColumnInPage(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.02.00.01.02")]
|
||||
public class AddLanguageTable : MultiDatabaseMigration
|
||||
{
|
||||
public AddLanguageTable(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public AddLanguageTable(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.02.00.01.03")]
|
||||
public class UpdatePageAndAddColumnToSite : MultiDatabaseMigration
|
||||
{
|
||||
public UpdatePageAndAddColumnToSite(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public UpdatePageAndAddColumnToSite(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.02.00.02.01")]
|
||||
|
||||
public class AddSiteGuidToSite : MultiDatabaseMigration
|
||||
{
|
||||
public AddSiteGuidToSite(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public AddSiteGuidToSite(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.02.00.02.02")]
|
||||
public class UpdateDefaultContainerTypeInSitePage : MultiDatabaseMigration
|
||||
{
|
||||
public UpdateDefaultContainerTypeInSitePage(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
//Update DefaultContainerType In Site
|
||||
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'");
|
||||
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'");
|
||||
|
||||
//Update DefaultContainerType in Page
|
||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'");
|
||||
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'");
|
||||
|
||||
//Update ContainerType in PageModule
|
||||
var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'");
|
||||
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.02.00.02.03")]
|
||||
public class DropDefaultLayoutInSite : MultiDatabaseMigration
|
||||
{
|
||||
public DropDefaultLayoutInSite(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
//Alter Column in Setting table for Sql Server
|
||||
var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
settingEntityBuilder.DropIndex("IX_Setting");
|
||||
settingEntityBuilder.AlterStringColumn("SettingName", 200);
|
||||
settingEntityBuilder.AddIndex("IX_Setting", new [] {"EntityName", "EntityId", "SettingName"}, true);
|
||||
|
||||
//Drop Column from Site Table
|
||||
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
siteEntityBuilder.DropColumn("DefaultLayoutType");
|
||||
|
||||
//Update DefaultContainerType In Site
|
||||
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'");
|
||||
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'");
|
||||
|
||||
//Drop Column from Page Table
|
||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
pageEntityBuilder.DropColumn("LayoutType");
|
||||
|
||||
//Update DefaultContainerType in Page
|
||||
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'");
|
||||
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'");
|
||||
|
||||
|
||||
//Update ContainerType in PageModule
|
||||
var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'");
|
||||
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.02.01.00.00")]
|
||||
|
||||
public class AddAppVersionsTable : MultiDatabaseMigration
|
||||
{
|
||||
public AddAppVersionsTable(IEnumerable<IOqtaneDatabase> databases) : base(databases)
|
||||
public AddAppVersionsTable(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
@ -24,7 +22,7 @@ namespace Oqtane.Migrations
|
||||
appVersionsEntityBuilder.Create();
|
||||
|
||||
//Finish SqlServer Migration from DbUp
|
||||
if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB")
|
||||
if (ActiveDatabase.Name == "SqlServer")
|
||||
{
|
||||
//Version 1.0.0
|
||||
InsertVersion(migrationBuilder, "01.00.00", "Oqtane.Scripts.Master.00.09.00.00.sql");
|
||||
@ -59,7 +57,7 @@ namespace Oqtane.Migrations
|
||||
|
||||
migrationBuilder.Sql($@"
|
||||
INSERT INTO {appVersions}({version}, {appledDate})
|
||||
VALUES('02.01.00', '{DateTime.UtcNow:u}')
|
||||
VALUES('02.01.00', '{DateTime.UtcNow.ToString("yyyy'-'MM'-'dd HH':'mm':'ss")}')
|
||||
");
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user