improved file upload, enhanced module installation from Nuget to support upgrades, added ability to upgrade the framework from Nuget, completed isolated multitenancy and site alias management, created IPortable interface for importing data into modules, added default content to initial installation

This commit is contained in:
Shaun Walker
2019-10-08 16:11:23 -04:00
parent dce53e10b0
commit 9971510b1e
48 changed files with 961 additions and 157 deletions

View File

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization;
using Oqtane.Repository;
using Oqtane.Models;
using Oqtane.Shared;
using System.Linq;
namespace Oqtane.Controllers
{

View File

@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
@ -17,7 +18,25 @@ namespace Oqtane.Controllers
this.environment = environment;
}
// GET api/<controller>/current
// GET: api/<controller>?folder=x
[HttpGet]
public IEnumerable<string> Get(string folder)
{
List<string> files = new List<string>();
folder = folder.Replace("/", "\\");
if (folder.StartsWith("\\")) folder = folder.Substring(1);
folder = Path.Combine(environment.WebRootPath, folder);
if (Directory.Exists(folder))
{
foreach(string file in Directory.GetFiles(folder))
{
files.Add(file);
}
}
return files;
}
// POST api/<controller>/upload
[HttpPost("upload")]
public async Task UploadFile(string folder, IFormFile file)
{

View File

@ -1,9 +1,12 @@
using DbUp;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Oqtane.Infrastructure;
using Oqtane.Models;
using Oqtane.Shared;
using System;
using System.Data.SqlClient;
using System.IO;
@ -17,28 +20,41 @@ namespace Oqtane.Controllers
public class InstallationController : Controller
{
private readonly IConfigurationRoot Config;
private readonly IInstallationManager InstallationManager;
public InstallationController(IConfigurationRoot Config)
public InstallationController(IConfigurationRoot Config, IInstallationManager InstallationManager)
{
this.Config = Config;
this.InstallationManager = InstallationManager;
}
// POST api/<controller>
[HttpPost]
public GenericResponse Post([FromBody] string connectionString)
public GenericResponse Post([FromBody] string connectionstring)
{
var response = new GenericResponse { Success = false, Message = "" };
if (ModelState.IsValid)
{
bool exists = IsInstalled().Success;
bool master = false;
string defaultconnectionstring = Config.GetConnectionString("DefaultConnection");
if (string.IsNullOrEmpty(defaultconnectionstring) || connectionstring != defaultconnectionstring)
{
master = true;
}
bool exists = false;
if (master)
{
exists = IsInstalled().Success;
}
if (!exists)
{
string datadirectory = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
connectionString = connectionString.Replace("|DataDirectory|", datadirectory);
connectionstring = connectionstring.Replace("|DataDirectory|", datadirectory);
SqlConnection connection = new SqlConnection(connectionString);
SqlConnection connection = new SqlConnection(connectionstring);
try
{
using (connection)
@ -57,7 +73,7 @@ namespace Oqtane.Controllers
{
string masterConnectionString = "";
string databaseName = "";
string[] fragments = connectionString.Split(';', StringSplitOptions.RemoveEmptyEntries);
string[] fragments = connectionstring.Split(';', StringSplitOptions.RemoveEmptyEntries);
foreach (string fragment in fragments)
{
if (fragment.ToLower().Contains("initial catalog=") || fragment.ToLower().Contains("database="))
@ -79,7 +95,7 @@ namespace Oqtane.Controllers
{
connection.Open();
SqlCommand command;
if (connectionString.ToLower().Contains("attachdbfilename=")) // LocalDB
if (connectionstring.ToLower().Contains("attachdbfilename=")) // LocalDB
{
command = new SqlCommand("CREATE DATABASE [" + databaseName + "] ON ( NAME = '" + databaseName + "', FILENAME = '" + datadirectory + "\\" + databaseName + ".mdf')", connection);
}
@ -104,14 +120,17 @@ namespace Oqtane.Controllers
{
// get master initialization script and update connectionstring and alias in seed data
string initializationScript = "";
using (StreamReader reader = new StreamReader(Directory.GetCurrentDirectory() + "\\Scripts\\Master.sql"))
if (master)
{
initializationScript = reader.ReadToEnd();
using (StreamReader reader = new StreamReader(Directory.GetCurrentDirectory() + "\\Scripts\\Master.sql"))
{
initializationScript = reader.ReadToEnd();
}
initializationScript = initializationScript.Replace("{ConnectionString}", connectionstring);
initializationScript = initializationScript.Replace("{Alias}", HttpContext.Request.Host.Value);
}
initializationScript = initializationScript.Replace("{ConnectionString}", connectionString);
initializationScript = initializationScript.Replace("{Alias}", HttpContext.Request.Host.Value);
var dbUpgradeConfig = DeployChanges.To.SqlDatabase(connectionString)
var dbUpgradeConfig = DeployChanges.To.SqlDatabase(connectionstring)
.WithScript(new DbUp.Engine.SqlScript("Master.sql", initializationScript))
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly()); // tenant scripts should be added to /Scripts folder as Embedded Resources
var dbUpgrade = dbUpgradeConfig.Build();
@ -125,19 +144,22 @@ namespace Oqtane.Controllers
else
{
// update appsettings
string config = "";
using (StreamReader reader = new StreamReader(Directory.GetCurrentDirectory() + "\\appsettings.json"))
if (master)
{
config = reader.ReadToEnd();
string config = "";
using (StreamReader reader = new StreamReader(Directory.GetCurrentDirectory() + "\\appsettings.json"))
{
config = reader.ReadToEnd();
}
connectionstring = connectionstring.Replace(datadirectory, "|DataDirectory|");
connectionstring = connectionstring.Replace(@"\", @"\\");
config = config.Replace("DefaultConnection\": \"", "DefaultConnection\": \"" + connectionstring);
using (StreamWriter writer = new StreamWriter(Directory.GetCurrentDirectory() + "\\appsettings.json"))
{
writer.WriteLine(config);
}
Config.Reload();
}
connectionString = connectionString.Replace(datadirectory, "|DataDirectory|");
connectionString = connectionString.Replace(@"\", @"\\");
config = config.Replace("DefaultConnection\": \"", "DefaultConnection\": \"" + connectionString);
using (StreamWriter writer = new StreamWriter(Directory.GetCurrentDirectory() + "\\appsettings.json"))
{
writer.WriteLine(config);
}
Config.Reload();
response.Success = true;
}
}
@ -235,6 +257,15 @@ namespace Oqtane.Controllers
}
}
}
[HttpGet("upgrade")]
[Authorize(Roles = Constants.HostRole)]
public GenericResponse Upgrade()
{
var response = new GenericResponse { Success = true, Message = "" };
InstallationManager.InstallPackages("Framework");
return response;
}
}
public class InstallationContext : DbContext

View File

@ -4,6 +4,12 @@ using Microsoft.AspNetCore.Authorization;
using Oqtane.Repository;
using Oqtane.Models;
using Oqtane.Shared;
using System.Linq;
using System.Reflection;
using System;
using Oqtane.Modules;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json;
namespace Oqtane.Controllers
{
@ -12,24 +18,28 @@ namespace Oqtane.Controllers
{
private readonly IModuleRepository Modules;
private readonly IPageModuleRepository PageModules;
private readonly IModuleDefinitionRepository ModuleDefinitions;
private readonly IServiceProvider ServiceProvider;
public ModuleController(IModuleRepository Modules, IPageModuleRepository PageModules)
public ModuleController(IModuleRepository Modules, IPageModuleRepository PageModules, IModuleDefinitionRepository ModuleDefinitions, IServiceProvider ServiceProvider)
{
this.Modules = Modules;
this.PageModules = PageModules;
this.ModuleDefinitions = ModuleDefinitions;
this.ServiceProvider = ServiceProvider;
}
// GET: api/<controller>?pageid=x
// GET: api/<controller>?siteid=x&moduledefinitionname=x
[HttpGet]
public IEnumerable<Module> Get(string pageid, string siteid, string moduledefinitionname)
public IEnumerable<Models.Module> Get(string pageid, string siteid, string moduledefinitionname)
{
if (!string.IsNullOrEmpty(pageid))
{
List<Module> modulelist = new List<Module>();
List<Models.Module> modulelist = new List<Models.Module>();
foreach (PageModule pagemodule in PageModules.GetPageModules(int.Parse(pageid)))
{
Module module = pagemodule.Module;
Models.Module module = pagemodule.Module;
module.PageModuleId = pagemodule.PageModuleId;
module.PageId = pagemodule.PageId;
module.Title = pagemodule.Title;
@ -48,7 +58,7 @@ namespace Oqtane.Controllers
// GET api/<controller>/5
[HttpGet("{id}")]
public Module Get(int id)
public Models.Module Get(int id)
{
return Modules.GetModule(id);
}
@ -56,7 +66,7 @@ namespace Oqtane.Controllers
// POST api/<controller>
[HttpPost]
[Authorize(Roles = Constants.AdminRole)]
public Module Post([FromBody] Module Module)
public Models.Module Post([FromBody] Models.Module Module)
{
if (ModelState.IsValid)
{
@ -68,7 +78,7 @@ namespace Oqtane.Controllers
// PUT api/<controller>/5
[HttpPut("{id}")]
[Authorize(Roles = Constants.AdminRole)]
public Module Put(int id, [FromBody] Module Module)
public Models.Module Put(int id, [FromBody] Models.Module Module)
{
if (ModelState.IsValid)
{
@ -84,5 +94,103 @@ namespace Oqtane.Controllers
{
Modules.DeleteModule(id);
}
// GET api/<controller>/export?moduleid=x
[HttpGet("export")]
[Authorize(Roles = Constants.AdminRole)]
public string Export(int moduleid)
{
string content = "";
try
{
Models.Module module = Modules.GetModule(moduleid);
if (module != null)
{
List<ModuleDefinition> moduledefinitions = ModuleDefinitions.GetModuleDefinitions(module.SiteId).ToList();
ModuleDefinition moduledefinition = moduledefinitions.Where(item => item.ModuleDefinitionName == module.ModuleDefinitionName).FirstOrDefault();
if (moduledefinition != null)
{
ModuleContent modulecontent = new ModuleContent();
modulecontent.ModuleDefinitionName = moduledefinition.ModuleDefinitionName;
modulecontent.Version = moduledefinition.Version;
modulecontent.Content = "";
if (moduledefinition.ServerAssemblyName != "")
{
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies()
.Where(item => item.FullName.StartsWith(moduledefinition.ServerAssemblyName)).FirstOrDefault();
if (assembly != null)
{
Type moduletype = assembly.GetTypes()
.Where(item => item.Namespace != null)
.Where(item => item.Namespace.StartsWith(moduledefinition.ModuleDefinitionName.Substring(0, moduledefinition.ModuleDefinitionName.IndexOf(","))))
.Where(item => item.GetInterfaces().Contains(typeof(IPortable))).FirstOrDefault();
if (moduletype != null)
{
var moduleobject = ActivatorUtilities.CreateInstance(ServiceProvider, moduletype);
modulecontent.Content = ((IPortable)moduleobject).ExportModule(module);
}
}
}
content = JsonSerializer.Serialize(modulecontent);
}
}
}
catch
{
// error occurred during export
}
return content;
}
// POST api/<controller>/import?moduleid=x
[HttpPost("import")]
[Authorize(Roles = Constants.AdminRole)]
public bool Import(int moduleid, [FromBody] string Content)
{
bool success = false;
if (ModelState.IsValid)
{
try
{
Models.Module module = Modules.GetModule(moduleid);
if (module != null)
{
List<ModuleDefinition> moduledefinitions = ModuleDefinitions.GetModuleDefinitions(module.SiteId).ToList();
ModuleDefinition moduledefinition = moduledefinitions.Where(item => item.ModuleDefinitionName == module.ModuleDefinitionName).FirstOrDefault();
if (moduledefinition != null)
{
ModuleContent modulecontent = JsonSerializer.Deserialize<ModuleContent>(Content);
if (modulecontent.ModuleDefinitionName == moduledefinition.ModuleDefinitionName)
{
if (moduledefinition.ServerAssemblyName != "")
{
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies()
.Where(item => item.FullName.StartsWith(moduledefinition.ServerAssemblyName)).FirstOrDefault();
if (assembly != null)
{
Type moduletype = assembly.GetTypes()
.Where(item => item.Namespace != null)
.Where(item => item.Namespace.StartsWith(moduledefinition.ModuleDefinitionName.Substring(0, moduledefinition.ModuleDefinitionName.IndexOf(","))))
.Where(item => item.GetInterfaces().Contains(typeof(IPortable))).FirstOrDefault();
if (moduletype != null)
{
var moduleobject = ActivatorUtilities.CreateInstance(ServiceProvider, moduletype);
((IPortable)moduleobject).ImportModule(module, modulecontent.Content, modulecontent.Version);
success = true;
}
}
}
}
}
}
}
catch
{
// error occurred during import
}
}
return success;
}
}
}

View File

@ -9,6 +9,8 @@ using System.Threading;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Authorization;
using Oqtane.Shared;
namespace Oqtane.Controllers
{
@ -24,6 +26,7 @@ namespace Oqtane.Controllers
// GET: api/<controller>?tag=x
[HttpGet]
[Authorize(Roles = Constants.HostRole)]
public async Task<IEnumerable<Package>> Get(string tag)
{
List<Package> packages = new List<Package>();
@ -52,6 +55,7 @@ namespace Oqtane.Controllers
}
[HttpPost]
[Authorize(Roles = Constants.HostRole)]
public async Task Post(string packageid, string version, string folder)
{
using (var httpClient = new HttpClient())