renamed control to action to reflect its purpose and be more consistent with asp.net conventions

This commit is contained in:
Shaun Walker 2019-10-19 11:09:10 -04:00
parent f6e70036b1
commit ce25967633
18 changed files with 401 additions and 30 deletions

View File

@ -19,7 +19,7 @@
{
ModuleState = Module; // passed in from Pane component
string container = ModuleState.ContainerType;
if (PageState.ModuleId != -1 && PageState.Control != "" && ModuleState.UseAdminContainer)
if (PageState.ModuleId != -1 && PageState.Action != "" && ModuleState.UseAdminContainer)
{
container = Constants.DefaultAdminContainer;
}
@ -35,7 +35,7 @@
else
{
// container does not exist with type specified
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageControl));
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageComponent));
builder.AddAttribute(1, "Message", "Error Loading Module Container " + container);
builder.CloseComponent();
}

View File

@ -30,9 +30,9 @@
{
string typename = ModuleState.ModuleType;
// check for core module actions component
if (Constants.DefaultModuleActions.Contains(PageState.Control))
if (Constants.DefaultModuleActions.Contains(PageState.Action))
{
typename = Constants.DefaultModuleActionsTemplate.Replace("{Control}", PageState.Control);
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, PageState.Action);
}
Type moduleType = null;

View File

@ -18,7 +18,7 @@ namespace Oqtane.Shared
public Uri Uri { get; set; }
public Dictionary<string, string> QueryString { get; set; }
public int ModuleId { get; set; }
public string Control { get; set; }
public string Action { get; set; }
public bool EditMode { get; set; }
public bool DesignMode { get; set; }
}

View File

@ -38,7 +38,7 @@
DynamicComponent = builder =>
{
if (PageState.ModuleId != -1 && PageState.Control != "")
if (PageState.ModuleId != -1 && PageState.Action != "")
{
if (Name.ToLower() == Constants.AdminPane.ToLower())
{
@ -47,15 +47,15 @@
{
string typename = module.ModuleType;
// check for core module actions component
if (Constants.DefaultModuleActions.Contains(PageState.Control))
if (Constants.DefaultModuleActions.Contains(PageState.Action))
{
typename = Constants.DefaultModuleActionsTemplate.Replace("{Control}", PageState.Control);
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, PageState.Action);
}
Type moduleType = Type.GetType(typename);
if (moduleType != null)
{
bool authorized = false;
if (Constants.DefaultModuleActions.Contains(PageState.Control))
if (Constants.DefaultModuleActions.Contains(PageState.Action))
{
authorized = UserSecurity.IsAuthorized(PageState.User, "Edit", PageState.Page.Permissions);
}
@ -83,7 +83,7 @@
}
if (authorized)
{
if (!Constants.DefaultModuleActions.Contains(PageState.Control) && module.ControlTitle != "")
if (!Constants.DefaultModuleActions.Contains(PageState.Action) && module.ControlTitle != "")
{
module.Title = module.ControlTitle;
}

View File

@ -77,7 +77,7 @@
User user;
List<Module> modules;
int moduleid = -1;
string control = "";
string action = "";
bool editmode = false;
bool designmode = false;
Reload reload = Reload.None;
@ -162,9 +162,9 @@
// check if path has moduleid and control specification ie. page/moduleid/control/
if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result))
{
control = segments[segments.Length - 1];
action = segments[segments.Length - 1];
moduleid = result;
path = path.Replace(moduleid.ToString() + "/" + control + "/", "");
path = path.Replace(moduleid.ToString() + "/" + action + "/", "");
}
else
{
@ -235,9 +235,9 @@
pagestate.Uri = new Uri(_absoluteUri, UriKind.Absolute);
pagestate.QueryString = querystring;
pagestate.ModuleId = moduleid;
pagestate.Control = control;
pagestate.Action = action;
if (PageState != null && (PageState.ModuleId != pagestate.ModuleId || PageState.Control != pagestate.Control))
if (PageState != null && (PageState.ModuleId != pagestate.ModuleId || PageState.Action != pagestate.Action))
{
reload = Reload.Page;
}
@ -245,7 +245,7 @@
if (PageState == null || reload >= Reload.Page)
{
modules = await ModuleService.GetModulesAsync(site.SiteId);
modules = ProcessModules(modules, moduledefinitions, page.PageId, pagestate.ModuleId, pagestate.Control, page.Panes, site.DefaultContainerType);
modules = ProcessModules(modules, moduledefinitions, page.PageId, pagestate.ModuleId, pagestate.Action, page.Panes, site.DefaultContainerType);
}
else
{
@ -365,7 +365,7 @@
}
}
}
module.ModuleType = typename.Replace("{Control}", control);
module.ModuleType = typename.Replace(Constants.ActionToken, control);
// admin controls need to load additional metadata from the IModuleControl interface
if (moduleid == module.ModuleId)
@ -374,7 +374,7 @@
// check for core module actions component
if (Constants.DefaultModuleActions.Contains(control))
{
typename = Constants.DefaultModuleActionsTemplate.Replace("{Control}", control);
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, control);
}
Type moduletype = Type.GetType(typename);
if (moduletype != null)
@ -389,7 +389,7 @@
}
else
{
module.ModuleType = typename.Replace("{Control}", Constants.DefaultControl);
module.ModuleType = typename.Replace(Constants.ActionToken, Constants.DefaultAction);
}
}

View File

@ -21,7 +21,7 @@
else
{
// theme does not exist with type specified
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageControl));
builder.OpenComponent(0, Type.GetType(Constants.ModuleMessageComponent));
builder.AddAttribute(1, "Message", "Error Loading Page Theme " + PageState.Page.ThemeType);
builder.CloseComponent();
}

View File

@ -10,9 +10,9 @@
{
title = ModuleState.Title;
// check for core module actions component
if (Constants.DefaultModuleActions.Contains(PageState.Control))
if (Constants.DefaultModuleActions.Contains(PageState.Action))
{
title = PageState.Control;
title = PageState.Action;
}
return Task.CompletedTask;
}

View File

@ -0,0 +1,36 @@
using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Oqtane.Logging
{
static public class DBLoggerExtensions
{
static public ILoggingBuilder AddDBLogger(this ILoggingBuilder builder)
{
builder.AddConfiguration();
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, DBLoggerProvider>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<DBLoggerOptions>, DBLoggerOptionsSetup>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IOptionsChangeTokenSource<DBLoggerOptions>, LoggerProviderOptionsChangeTokenSource<DBLoggerOptions, DBLoggerProvider>>());
return builder;
}
static public ILoggingBuilder AddDBLogger(this ILoggingBuilder builder, Action<DBLoggerOptions> configure)
{
if (configure == null)
{
throw new ArgumentNullException(nameof(configure));
}
builder.AddDBLogger();
builder.Services.Configure(configure);
return builder;
}
}
}

View File

@ -0,0 +1,13 @@
using Microsoft.Extensions.Logging;
namespace Oqtane.Logging
{
public class DBLoggerOptions
{
public DBLoggerOptions()
{
}
public LogLevel LogLevel { get; set; } = LogLevel.Information;
}
}

View File

@ -0,0 +1,11 @@
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging.Configuration;
namespace Oqtane.Logging
{
internal class DBLoggerOptionsSetup : ConfigureFromConfigurationOptions<DBLoggerOptions>
{
public DBLoggerOptionsSetup(ILoggerProviderConfiguration<DBLoggerProvider> providerConfiguration)
: base(providerConfiguration.Configuration) {}
}
}

View File

@ -0,0 +1,94 @@
using System;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using Oqtane.Models;
using Oqtane.Repository;
namespace Oqtane.Logging
{
[Microsoft.Extensions.Logging.ProviderAlias("DB")]
public class DBLoggerProvider : LoggerProvider
{
bool Terminated;
ConcurrentQueue<LogEntry> LogQueue = new ConcurrentQueue<LogEntry>();
private Tenant tenant;
internal DBLoggerOptions Settings { get; private set; }
public DBLoggerProvider(ITenantResolver TenantResolver)
{
tenant = TenantResolver.GetTenant();
}
public override void WriteLog(LogEntry LogEntry)
{
// enrich with tenant information
LogQueue.Enqueue(LogEntry);
}
void ThreadProc()
{
Task.Run(() => {
while (!Terminated)
{
try
{
AddLogEntry();
System.Threading.Thread.Sleep(100);
}
catch
{
}
}
});
}
void AddLogEntry()
{
// check the LogQueue.Count to determine if a threshold has been reached
// then dequeue the items into temp storage based on TenantId and bulk insert them into the database
LogEntry logentry = null;
if (LogQueue.TryDequeue(out logentry))
{
// convert logentry object to object which can be stored in database
}
}
protected override void Dispose(bool Disposing)
{
Terminated = true;
base.Dispose(Disposing);
}
public DBLoggerProvider(IOptionsMonitor<DBLoggerOptions> Settings)
: this(Settings.CurrentValue)
{
SettingsChangeToken = Settings.OnChange(settings => {
this.Settings = settings;
});
}
public DBLoggerProvider(DBLoggerOptions Settings)
{
this.Settings = Settings;
ThreadProc();
}
public override bool IsEnabled(LogLevel LogLevel)
{
bool Result = LogLevel != LogLevel.None
&& this.Settings.LogLevel != LogLevel.None
&& Convert.ToInt32(LogLevel) >= Convert.ToInt32(this.Settings.LogLevel);
return Result;
}
}
}

View File

@ -0,0 +1,32 @@
using Microsoft.Extensions.Logging;
using Oqtane.Models;
using Oqtane.Repository;
using System;
using System.Collections.Generic;
namespace Oqtane.Logging
{
public class LogEntry
{
public LogEntry()
{
TimeStampUtc = DateTime.UtcNow;
UserName = Environment.UserName;
}
static public readonly string StaticHostName = System.Net.Dns.GetHostName();
public string UserName { get; private set; }
public string HostName { get { return StaticHostName; } }
public DateTime TimeStampUtc { get; private set; }
public string Category { get; set; }
public LogLevel Level { get; set; }
public string Text { get; set; }
public Exception Exception { get; set; }
public EventId EventId { get; set; }
public object State { get; set; }
public string StateText { get; set; }
public Dictionary<string, object> StateProperties { get; set; }
public List<LogScope> Scopes { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Oqtane.Logging
{
public class LogScope
{
public string Text { get; set; }
public Dictionary<string, object> Properties { get; set; }
}
}

View File

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
namespace Oqtane.Logging
{
internal class Logger : ILogger
{
public LoggerProvider Provider { get; private set; }
public string Category { get; private set; }
public Logger(LoggerProvider Provider, string Category)
{
this.Provider = Provider;
this.Category = Category;
}
IDisposable ILogger.BeginScope<TState>(TState State)
{
return Provider.ScopeProvider.Push(State);
}
bool ILogger.IsEnabled(LogLevel LogLevel)
{
return Provider.IsEnabled(LogLevel);
}
void ILogger.Log<TState>(LogLevel LogLevel, EventId EventId, TState State, Exception Exception, Func<TState, Exception, string> Formatter)
{
if ((this as ILogger).IsEnabled(LogLevel))
{
LogEntry logentry = new LogEntry();
// we need the TenantId and SiteId
logentry.Category = this.Category;
logentry.Level = LogLevel;
logentry.Text = Exception?.Message ?? State.ToString();
logentry.Exception = Exception;
logentry.EventId = EventId;
logentry.State = State;
if (State is string)
{
logentry.StateText = State.ToString();
}
else if (State is IEnumerable<KeyValuePair<string, object>> Properties)
{
logentry.StateProperties = new Dictionary<string, object>();
foreach (KeyValuePair<string, object> item in Properties)
{
logentry.StateProperties[item.Key] = item.Value;
}
}
if (Provider.ScopeProvider != null)
{
Provider.ScopeProvider.ForEachScope((value, loggingProps) =>
{
if (logentry.Scopes == null)
{
logentry.Scopes = new List<LogScope>();
}
LogScope Scope = new LogScope();
logentry.Scopes.Add(Scope);
if (value is string)
{
Scope.Text = value.ToString();
}
else if (value is IEnumerable<KeyValuePair<string, object>> props)
{
if (Scope.Properties == null)
Scope.Properties = new Dictionary<string, object>();
foreach (var pair in props)
{
Scope.Properties[pair.Key] = pair.Value;
}
}
}, State);
}
Provider.WriteLog(logentry);
}
}
}
}

View File

@ -0,0 +1,80 @@
using System;
using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
namespace Oqtane.Logging
{
public abstract class LoggerProvider : IDisposable, ILoggerProvider, ISupportExternalScope
{
ConcurrentDictionary<string, Logger> loggers = new ConcurrentDictionary<string, Logger>();
IExternalScopeProvider fScopeProvider;
protected IDisposable SettingsChangeToken;
void ISupportExternalScope.SetScopeProvider(IExternalScopeProvider ScopeProvider)
{
fScopeProvider = ScopeProvider;
}
ILogger ILoggerProvider.CreateLogger(string Category)
{
return loggers.GetOrAdd(Category,
(category) => {
return new Logger(this, category);
});
}
void IDisposable.Dispose()
{
if (!this.IsDisposed)
{
try
{
Dispose(true);
}
catch
{
}
this.IsDisposed = true;
GC.SuppressFinalize(this);
}
}
protected virtual void Dispose(bool Disposing)
{
if (SettingsChangeToken != null)
{
SettingsChangeToken.Dispose();
SettingsChangeToken = null;
}
}
public LoggerProvider()
{
}
~LoggerProvider()
{
if (!this.IsDisposed)
{
Dispose(false);
}
}
public abstract bool IsEnabled(LogLevel LogLevel);
public abstract void WriteLog(LogEntry LogEntry);
internal IExternalScopeProvider ScopeProvider
{
get
{
if (fScopeProvider == null)
fScopeProvider = new LoggerExternalScopeProvider();
return fScopeProvider;
}
}
public bool IsDisposed { get; protected set; }
}
}

View File

@ -43,6 +43,7 @@
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.0-preview1.19506.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc3" />
</ItemGroup>

View File

@ -6,6 +6,7 @@ using System.Reflection;
using System;
using Oqtane.Modules;
using Microsoft.Extensions.Caching.Memory;
using Oqtane.Shared;
namespace Oqtane.Repository
{
@ -120,7 +121,7 @@ namespace Oqtane.Repository
Dependencies = GetProperty(properties, "Dependencies"),
PermissionNames = GetProperty(properties, "PermissionNames"),
ServerAssemblyName = GetProperty(properties, "ServerAssemblyName"),
ControlTypeTemplate = ModuleType + ".{Control}" + ", " + typename[1],
ControlTypeTemplate = ModuleType + "." + Constants.ActionToken + ", " + typename[1],
ControlTypeRoutes = "",
AssemblyName = assembly.FullName.Split(",")[0]
};
@ -141,7 +142,7 @@ namespace Oqtane.Repository
Dependencies = "",
PermissionNames = "",
ServerAssemblyName = "",
ControlTypeTemplate = ModuleType + ".{Control}" + ", " + typename[1],
ControlTypeTemplate = ModuleType + "." + Constants.ActionToken + ", " + typename[1],
ControlTypeRoutes = "",
AssemblyName = assembly.FullName.Split(",")[0]
};

View File

@ -13,15 +13,17 @@
public const string DefaultContainer = "Oqtane.Themes.BlazorTheme.Container, Oqtane.Client";
public const string DefaultAdminContainer = "Oqtane.Themes.AdminContainer, Oqtane.Client";
public const string ActionToken = "{Action}";
public const string DefaultAction = "Index";
public const string AdminPane = "Admin";
// Default Module Actions are reserved and should not be used by modules
public static readonly string[] DefaultModuleActions = new[] { "Settings", "Import", "Export" };
public const string DefaultModuleActionsTemplate = "Oqtane.Modules.Admin.Modules.{Control}, Oqtane.Client";
public static readonly string[] DefaultModuleActions = new[] { "Settings", "Import", "Export" };
public static readonly string DefaultModuleActionsTemplate = "Oqtane.Modules.Admin.Modules." + ActionToken + ", Oqtane.Client";
public const string AdminDashboardModule = "Oqtane.Modules.Admin.Dashboard, Oqtane.Client";
public const string PageManagementModule = "Oqtane.Modules.Admin.Pages, Oqtane.Client";
public const string ModuleMessageControl = "Oqtane.Modules.Controls.ModuleMessage, Oqtane.Client";
public const string DefaultControl = "Index";
public const string AdminPane = "Admin";
public const string ModuleMessageComponent = "Oqtane.Modules.Controls.ModuleMessage, Oqtane.Client";
public const string AllUsersRole = "All Users";
public const string HostRole = "Host Users";