Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
a6228f3704 | |||
572f2f6be1 | |||
db63447052 | |||
37c418a869 | |||
b3b39f583a | |||
92c554e854 | |||
391827222e | |||
c1721bd1a1 | |||
f6630ae241 | |||
424cab64a8 |
25
.gitea/workflows/build-container.yml
Normal file
25
.gitea/workflows/build-container.yml
Normal file
@ -0,0 +1,25 @@
|
||||
name: build-docker-imge
|
||||
on:
|
||||
- push
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build the docker container
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Git clone"
|
||||
run: git clone ${{ gitea.server_url }}/${{ gitea.repository }}.git .
|
||||
- name: "Git checkout"
|
||||
run: git checkout "${{ gitea.sha }}"
|
||||
- uses: aevea/action-kaniko@master
|
||||
name: Run Kaniko to build our api docker container.
|
||||
with:
|
||||
image: kocoded/oqtane.framework
|
||||
tag: ${{ git.workflow_sha }}
|
||||
tag_with_latest: github.ref == 'refs/heads/master'
|
||||
registry: git.kocoder.xyz
|
||||
username: ${{ secrets.CI_RUNNER_USER }}
|
||||
password: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||
build_file: Dockerfile
|
||||
target: deploy
|
||||
|
24
Dockerfile
Normal file
24
Dockerfile
Normal file
@ -0,0 +1,24 @@
|
||||
# Build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||
|
||||
WORKDIR /source
|
||||
|
||||
COPY --link . .
|
||||
|
||||
RUN dotnet restore /source/Oqtane.sln
|
||||
|
||||
RUN dotnet build "/source/Oqtane.sln" -c Release -o /source/build/
|
||||
|
||||
# Publish
|
||||
FROM build AS publish
|
||||
|
||||
RUN dotnet publish "Oqtane.Server/Oqtane.Server.csproj" -c Release -o /source/publish/
|
||||
|
||||
# Deploy
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS deploy
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
COPY --from=publish /source/publish/ /app/
|
||||
ENTRYPOINT ["dotnet", "Oqtane.Server.dll"]
|
9
Oqtane.Application/.gitignore
vendored
9
Oqtane.Application/.gitignore
vendored
@ -1,9 +0,0 @@
|
||||
.vs/
|
||||
bin/
|
||||
obj/
|
||||
*.user
|
||||
artifacts/
|
||||
msbuild.binlog
|
||||
.vscode/
|
||||
*.binlog
|
||||
*.nupkg
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/template",
|
||||
"author": "Shaun Walker",
|
||||
"classifications": [
|
||||
"Web",
|
||||
"ASP.NET",
|
||||
"Blazor",
|
||||
"Oqtane"
|
||||
],
|
||||
"tags": {
|
||||
"language": "C#",
|
||||
"type": "project"
|
||||
},
|
||||
"identity": "Oqtane.Application.Template",
|
||||
"name": "Oqtane Application Solution For Blazor",
|
||||
"shortName": "oqtane-app",
|
||||
"sourceName": "Oqtane.Application",
|
||||
"preferNameDirectory": true
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
[assembly: RootNamespace("Oqtane.Application.Client")]
|
@ -1,19 +0,0 @@
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Modules;
|
||||
|
||||
namespace Oqtane.Application.MyModule
|
||||
{
|
||||
public class ModuleInfo : IModule
|
||||
{
|
||||
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||
{
|
||||
Name = "MyModule",
|
||||
Description = "Example module",
|
||||
Version = "1.0.0",
|
||||
ServerManagerType = "Oqtane.Application.Manager.MyModuleManager, Oqtane.Application.Server.Oqtane",
|
||||
ReleaseVersions = "1.0.0",
|
||||
Dependencies = "Oqtane.Application.Shared.Oqtane",
|
||||
PackageName = "Oqtane.Application"
|
||||
};
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Version>1.0.0</Version>
|
||||
<AssemblyName>Oqtane.Application.Client.Oqtane</AssemblyName>
|
||||
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
|
||||
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
|
||||
<BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>
|
||||
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\Oqtane.Application.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Oqtane.Client" Version="6.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,13 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Application.Client
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
// defer client startup to Oqtane - do not modify
|
||||
await Oqtane.Client.Program.Main(args);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Name.Text" xml:space="preserve">
|
||||
<value>Name: </value>
|
||||
</data>
|
||||
<data name="Name.HelpText" xml:space="preserve">
|
||||
<value>Enter the name</value>
|
||||
</data>
|
||||
<data name="Save" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
</data>
|
||||
<data name="Cancel" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="Message.SaveValidation" xml:space="preserve">
|
||||
<value>Please Provide All Required Information</value>
|
||||
</data>
|
||||
<data name="Message.SaveError" xml:space="preserve">
|
||||
<value>Error Saving MyModule</value>
|
||||
</data>
|
||||
<data name="Message.LoadError" xml:space="preserve">
|
||||
<value>Error Loading MyModule</value>
|
||||
</data>
|
||||
</root>
|
@ -1,147 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Name" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="Add.Text" xml:space="preserve">
|
||||
<value>Add MyModule</value>
|
||||
</data>
|
||||
<data name="Edit.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="Delete.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="Delete.Header" xml:space="preserve">
|
||||
<value>Delete MyModule</value>
|
||||
</data>
|
||||
<data name="Delete.Message" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Delete This MyModule?</value>
|
||||
</data>
|
||||
<data name="Message.DisplayNone" xml:space="preserve">
|
||||
<value>No MyModules To Display</value>
|
||||
</data>
|
||||
<data name="Message.LoadError" xml:space="preserve">
|
||||
<value>Error Loading MyModule</value>
|
||||
</data>
|
||||
<data name="Message.DeleteError" xml:space="preserve">
|
||||
<value>Error Deleting MyModule</value>
|
||||
</data>
|
||||
</root>
|
@ -1,55 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Application.Services
|
||||
{
|
||||
public interface IMyModuleService
|
||||
{
|
||||
Task<List<Models.MyModule>> GetMyModulesAsync(int ModuleId);
|
||||
|
||||
Task<Models.MyModule> GetMyModuleAsync(int MyModuleId, int ModuleId);
|
||||
|
||||
Task<Models.MyModule> AddMyModuleAsync(Models.MyModule MyModule);
|
||||
|
||||
Task<Models.MyModule> UpdateMyModuleAsync(Models.MyModule MyModule);
|
||||
|
||||
Task DeleteMyModuleAsync(int MyModuleId, int ModuleId);
|
||||
}
|
||||
|
||||
public class MyModuleService : ServiceBase, IMyModuleService
|
||||
{
|
||||
public MyModuleService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
||||
|
||||
private string Apiurl => CreateApiUrl("MyModule");
|
||||
|
||||
public async Task<List<Models.MyModule>> GetMyModulesAsync(int ModuleId)
|
||||
{
|
||||
List<Models.MyModule> Tasks = await GetJsonAsync<List<Models.MyModule>>(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", EntityNames.Module, ModuleId), Enumerable.Empty<Models.MyModule>().ToList());
|
||||
return Tasks.OrderBy(item => item.Name).ToList();
|
||||
}
|
||||
|
||||
public async Task<Models.MyModule> GetMyModuleAsync(int MyModuleId, int ModuleId)
|
||||
{
|
||||
return await GetJsonAsync<Models.MyModule>(CreateAuthorizationPolicyUrl($"{Apiurl}/{MyModuleId}/{ModuleId}", EntityNames.Module, ModuleId));
|
||||
}
|
||||
|
||||
public async Task<Models.MyModule> AddMyModuleAsync(Models.MyModule MyModule)
|
||||
{
|
||||
return await PostJsonAsync<Models.MyModule>(CreateAuthorizationPolicyUrl($"{Apiurl}", EntityNames.Module, MyModule.ModuleId), MyModule);
|
||||
}
|
||||
|
||||
public async Task<Models.MyModule> UpdateMyModuleAsync(Models.MyModule MyModule)
|
||||
{
|
||||
return await PutJsonAsync<Models.MyModule>(CreateAuthorizationPolicyUrl($"{Apiurl}/{MyModule.MyModuleId}", EntityNames.Module, MyModule.ModuleId), MyModule);
|
||||
}
|
||||
|
||||
public async Task DeleteMyModuleAsync(int MyModuleId, int ModuleId)
|
||||
{
|
||||
await DeleteAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{MyModuleId}/{ModuleId}", EntityNames.Module, ModuleId));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Linq;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Application.Services;
|
||||
|
||||
namespace Oqtane.Application.Startup
|
||||
{
|
||||
public class ClientStartup : IClientStartup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
if (!services.Any(s => s.ServiceType == typeof(IMyModuleService)))
|
||||
{
|
||||
services.AddScoped<IMyModuleService, MyModuleService>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Themes;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Application.MyTheme
|
||||
{
|
||||
public class ThemeInfo : ITheme
|
||||
{
|
||||
public Oqtane.Models.Theme Theme => new Oqtane.Models.Theme
|
||||
{
|
||||
Name = "MyTheme",
|
||||
Version = "1.0.0",
|
||||
PackageName = "Oqtane.Application",
|
||||
ThemeSettingsType = "Oqtane.Application.MyTheme.ThemeSettings, Oqtane.Application.Client.Oqtane",
|
||||
ContainerSettingsType = "Oqtane.Application.MyTheme.ContainerSettings, Oqtane.Application.Client.Oqtane",
|
||||
Resources = new List<Resource>()
|
||||
{
|
||||
new Stylesheet(Constants.BootstrapStylesheetUrl, Constants.BootstrapStylesheetIntegrity, "anonymous"),
|
||||
new Stylesheet("~/Theme.css"),
|
||||
new Script(Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Application.Template</id>
|
||||
<version>6.2.0</version>
|
||||
<title>Oqtane Application Template For Blazor</title>
|
||||
<authors>Shaun Walker</authors>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
|
||||
<icon>icon.png</icon>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<description>Oqtane is an open source CMS and Application Framework that provides advanced functionality for developing web, mobile, and desktop applications on .NET. It leverages Blazor to compose a fully dynamic digital experience which can be hosted on Static Blazor, Blazor Server, Blazor WebAssembly, or Blazor Hybrid (via .NET MAUI).</description>
|
||||
<language>en-US</language>
|
||||
<tags>Web ASP.NET Blazor Oqtane Modular Multi-Tenant "Open Source" "SQL Server" MySQL PostgreSQL SQLite</tags>
|
||||
<readme>README.md</readme>
|
||||
<packageTypes>
|
||||
<packageType name="Template" />
|
||||
</packageTypes>
|
||||
</metadata>
|
||||
</package>
|
@ -1,33 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.12.35506.116 d17.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oqtane.Application.Server", "Server\Oqtane.Application.Server.csproj", "{04B05448-788F-433D-92C0-FED35122D45A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oqtane.Application.Client", "Client\Oqtane.Application.Client.csproj", "{AA8E58A1-CD09-4208-BF66-A8BB341FD669}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oqtane.Application.Shared", "Shared\Oqtane.Application.Shared.csproj", "{18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{04B05448-788F-433D-92C0-FED35122D45A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{04B05448-788F-433D-92C0-FED35122D45A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{04B05448-788F-433D-92C0-FED35122D45A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{04B05448-788F-433D-92C0-FED35122D45A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,19 +0,0 @@
|
||||
# Oqtane Application Template
|
||||
|
||||
This is a Visual Studio Project Template designed for Oqtane development projects. This template relies on the native templating capabilities of the .NET Command Line Interface (CLI):
|
||||
|
||||
```
|
||||
dotnet new install Oqtane.Application.Template
|
||||
dotnet new oqtane-app -o MyCompany.MyProject
|
||||
```
|
||||
|
||||
When using this approach you do not need to have a local copy of the oqtane.framework source code - you simply utilize Oqtane as a standard application dependency.
|
||||
|
||||
The solution contains an AppHost project which must be identified as the Startup project. It is responsible for loading the development environment and launching the Oqtane framework.
|
||||
|
||||
The solution also contains Build, Client, Server, and Shared folders which is where you you would implement your custom functionality. An example module and theme are included for reference, and you can add additional modules and themes within the same projects by following the standard Oqtane folder/namespace conventions.
|
||||
|
||||
*Known Issues*
|
||||
|
||||
- do not use the term "Oqtane" in your output name or else you will experience namespace conflicts
|
||||
|
@ -1,3 +0,0 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
[assembly: RootNamespace("Oqtane.Application.Server")]
|
@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Oqtane.Modules;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Application.Repository;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Application.Manager
|
||||
{
|
||||
public class MyModuleManager : MigratableModuleBase, IInstallable, IPortable, ISearchable
|
||||
{
|
||||
private readonly IMyModuleRepository _MyModuleRepository;
|
||||
private readonly IDBContextDependencies _DBContextDependencies;
|
||||
|
||||
public MyModuleManager(IMyModuleRepository MyModuleRepository, IDBContextDependencies DBContextDependencies)
|
||||
{
|
||||
_MyModuleRepository = MyModuleRepository;
|
||||
_DBContextDependencies = DBContextDependencies;
|
||||
}
|
||||
|
||||
public bool Install(Tenant tenant, string version)
|
||||
{
|
||||
return Migrate(new Context(_DBContextDependencies), tenant, MigrationType.Up);
|
||||
}
|
||||
|
||||
public bool Uninstall(Tenant tenant)
|
||||
{
|
||||
return Migrate(new Context(_DBContextDependencies), tenant, MigrationType.Down);
|
||||
}
|
||||
|
||||
public string ExportModule(Module module)
|
||||
{
|
||||
string content = "";
|
||||
List<Models.MyModule> MyModules = _MyModuleRepository.GetMyModules(module.ModuleId).ToList();
|
||||
if (MyModules != null)
|
||||
{
|
||||
content = JsonSerializer.Serialize(MyModules);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
public void ImportModule(Module module, string content, string version)
|
||||
{
|
||||
List<Models.MyModule> MyModules = null;
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
MyModules = JsonSerializer.Deserialize<List<Models.MyModule>>(content);
|
||||
}
|
||||
if (MyModules != null)
|
||||
{
|
||||
foreach(var Task in MyModules)
|
||||
{
|
||||
_MyModuleRepository.AddMyModule(new Models.MyModule { ModuleId = module.ModuleId, Name = Task.Name });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task<List<SearchContent>> GetSearchContentsAsync(PageModule pageModule, DateTime lastIndexedOn)
|
||||
{
|
||||
var searchContentList = new List<SearchContent>();
|
||||
|
||||
foreach (var MyModule in _MyModuleRepository.GetMyModules(pageModule.ModuleId))
|
||||
{
|
||||
if (MyModule.ModifiedOn >= lastIndexedOn)
|
||||
{
|
||||
searchContentList.Add(new SearchContent
|
||||
{
|
||||
EntityName = "MyModule",
|
||||
EntityId = MyModule.MyModuleId.ToString(),
|
||||
Title = MyModule.Name,
|
||||
Body = MyModule.Name,
|
||||
ContentModifiedBy = MyModule.ModifiedBy,
|
||||
ContentModifiedOn = MyModule.ModifiedOn
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(searchContentList);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Version>1.0.0</Version>
|
||||
<AssemblyName>Oqtane.Application.Server.Oqtane</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Client\Oqtane.Application.Client.csproj" />
|
||||
<ProjectReference Include="..\Shared\Oqtane.Application.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Oqtane.Server" Version="6.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,42 +0,0 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Oqtane.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Oqtane.Application.Server
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// defer server startup to Oqtane - do not modify
|
||||
var host = BuildWebHost(args);
|
||||
var databaseManager = host.Services.GetService<IDatabaseManager>();
|
||||
var install = databaseManager.Install();
|
||||
if (!string.IsNullOrEmpty(install.Message))
|
||||
{
|
||||
var filelogger = host.Services.GetRequiredService<ILogger<Program>>();
|
||||
if (filelogger != null)
|
||||
{
|
||||
filelogger.LogError($"[Oqtane.Application.Server.Program.Main] {install.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
|
||||
public static IWebHost BuildWebHost(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseConfiguration(new ConfigurationBuilder()
|
||||
.AddCommandLine(args)
|
||||
.AddEnvironmentVariables()
|
||||
.Build())
|
||||
.UseStartup<Startup>()
|
||||
.ConfigureLocalizationSettings()
|
||||
.Build();
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Oqtane.Modules;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Repository.Databases.Interfaces;
|
||||
|
||||
namespace Oqtane.Application.Repository
|
||||
{
|
||||
public class Context : DBContextBase, ITransientService, IMultiDatabase
|
||||
{
|
||||
public virtual DbSet<Models.MyModule> MyModule { get; set; }
|
||||
|
||||
public Context(IDBContextDependencies DBContextDependencies) : base(DBContextDependencies)
|
||||
{
|
||||
// ContextBase handles multi-tenant database connections
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
|
||||
builder.Entity<Models.MyModule>().ToTable(ActiveDatabase.RewriteName("MyModule"));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Modules;
|
||||
|
||||
namespace Oqtane.Application.Repository
|
||||
{
|
||||
public interface IMyModuleRepository
|
||||
{
|
||||
IEnumerable<Models.MyModule> GetMyModules(int ModuleId);
|
||||
Models.MyModule GetMyModule(int MyModuleId);
|
||||
Models.MyModule GetMyModule(int MyModuleId, bool tracking);
|
||||
Models.MyModule AddMyModule(Models.MyModule MyModule);
|
||||
Models.MyModule UpdateMyModule(Models.MyModule MyModule);
|
||||
void DeleteMyModule(int MyModuleId);
|
||||
}
|
||||
|
||||
public class MyModuleRepository : IMyModuleRepository, ITransientService
|
||||
{
|
||||
private readonly IDbContextFactory<Context> _factory;
|
||||
|
||||
public MyModuleRepository(IDbContextFactory<Context> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public IEnumerable<Models.MyModule> GetMyModules(int ModuleId)
|
||||
{
|
||||
using var db = _factory.CreateDbContext();
|
||||
return db.MyModule.Where(item => item.ModuleId == ModuleId).ToList();
|
||||
}
|
||||
|
||||
public Models.MyModule GetMyModule(int MyModuleId)
|
||||
{
|
||||
return GetMyModule(MyModuleId, true);
|
||||
}
|
||||
|
||||
public Models.MyModule GetMyModule(int MyModuleId, bool tracking)
|
||||
{
|
||||
using var db = _factory.CreateDbContext();
|
||||
if (tracking)
|
||||
{
|
||||
return db.MyModule.Find(MyModuleId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return db.MyModule.AsNoTracking().FirstOrDefault(item => item.MyModuleId == MyModuleId);
|
||||
}
|
||||
}
|
||||
|
||||
public Models.MyModule AddMyModule(Models.MyModule MyModule)
|
||||
{
|
||||
using var db = _factory.CreateDbContext();
|
||||
db.MyModule.Add(MyModule);
|
||||
db.SaveChanges();
|
||||
return MyModule;
|
||||
}
|
||||
|
||||
public Models.MyModule UpdateMyModule(Models.MyModule MyModule)
|
||||
{
|
||||
using var db = _factory.CreateDbContext();
|
||||
db.Entry(MyModule).State = EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
return MyModule;
|
||||
}
|
||||
|
||||
public void DeleteMyModule(int MyModuleId)
|
||||
{
|
||||
using var db = _factory.CreateDbContext();
|
||||
Models.MyModule MyModule = db.MyModule.Find(MyModuleId);
|
||||
db.MyModule.Remove(MyModule);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Oqtane.Extensions;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Shared;
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
|
||||
namespace Oqtane.Application.Server
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
private readonly IConfigurationRoot _configuration;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
|
||||
public Startup(IWebHostEnvironment environment)
|
||||
{
|
||||
AppDomain.CurrentDomain.SetData(Constants.DataDirectory, Path.Combine(environment.ContentRootPath, "Data"));
|
||||
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(environment.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", false, true)
|
||||
.AddJsonFile($"appsettings.{environment.EnvironmentName}.json", true, true)
|
||||
.AddEnvironmentVariables();
|
||||
|
||||
_configuration = builder.Build();
|
||||
_environment = environment;
|
||||
}
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// defer server startup to Oqtane - do not modify
|
||||
services.AddOqtane(_configuration, _environment);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IConfigurationRoot configuration, IWebHostEnvironment environment, ICorsService corsService, ICorsPolicyProvider corsPolicyProvider, ISyncManager sync)
|
||||
{
|
||||
// defer server startup to Oqtane - do not modify
|
||||
app.UseOqtane(configuration, environment, corsService, corsPolicyProvider, sync);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
/* Module Script */
|
||||
var App = App || {};
|
||||
|
||||
App.MyModule = {
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
.rz-text-editor {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.rz-html-editor-dropdown-items,
|
||||
.rz-popup,
|
||||
.rz-editor-dialog-wrapper {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
.rz-html-editor-dropdown-items .rz-html-editor-dropdown-item,
|
||||
.rz-html-editor-dropdown-items .rz-html-editor-dropdown-item > * {
|
||||
color: var(--rz-editor-button-color);
|
||||
}
|
||||
.rz-text-editor .rz-html-editor-dropdown .rz-html-editor-dropdown-value,
|
||||
.rz-text-editor .rz-html-editor-dropdown .rz-html-editor-dropdown-trigger,
|
||||
.rz-text-editor .rz-html-editor-colorpicker .rz-html-editor-color {
|
||||
color: var(--rz-editor-button-color);
|
||||
}
|
||||
.rz-text-editor .rz-colorpicker.rz-state-disabled {
|
||||
border: none !important;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 875 B |
@ -1,47 +0,0 @@
|
||||
var Oqtane = Oqtane || {};
|
||||
|
||||
Oqtane.RadzenTextEditor = {
|
||||
initialize: function (editor) {
|
||||
if (typeof Radzen.openPopup === "function" && Radzen.openPopup !== Oqtane.RadzenTextEditor.openPopup) {
|
||||
Oqtane.RadzenTextEditor.radzenOpenPopup = Radzen.openPopup;
|
||||
Radzen.openPopup = Oqtane.RadzenTextEditor.openPopup;
|
||||
}
|
||||
},
|
||||
openPopup: function () {
|
||||
Oqtane.RadzenTextEditor.radzenOpenPopup.apply(this, arguments);
|
||||
var id = arguments[1];
|
||||
var popup = document.getElementById(id);
|
||||
if (popup) {
|
||||
Oqtane.RadzenTextEditor.updateButtonStyles(popup);
|
||||
}
|
||||
},
|
||||
setBackgroundColor: function (editor, color) {
|
||||
editor.getElementsByClassName("rz-html-editor-content")[0].style.backgroundColor = color;
|
||||
},
|
||||
updateDialogLayout: function (editor) {
|
||||
var dialogs = editor.parentElement.getElementsByClassName('rz-dialog-wrapper');
|
||||
for (var dialog of dialogs) {
|
||||
document.body.appendChild(dialog);
|
||||
dialog.classList.add('rz-editor-dialog-wrapper', 'text-dark');
|
||||
|
||||
this.updateButtonStyles(dialog);
|
||||
}
|
||||
},
|
||||
updateButtonStyles: function (parent) {
|
||||
var primaryBtns = parent.getElementsByClassName('rz-primary');
|
||||
if (primaryBtns) {
|
||||
for (var btn of primaryBtns) {
|
||||
btn.classList.remove('rz-button', 'rz-primary');
|
||||
btn.classList.add('btn', 'btn-primary');
|
||||
}
|
||||
}
|
||||
|
||||
var secondaryBtns = parent.getElementsByClassName('rz-secondary');
|
||||
if (secondaryBtns) {
|
||||
for (var btn of secondaryBtns) {
|
||||
btn.classList.remove('rz-button', 'rz-secondary');
|
||||
btn.classList.add('btn', 'btn-secondary');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Version>1.0.0</Version>
|
||||
<AssemblyName>Oqtane.Application.Shared.Oqtane</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Oqtane.Shared" Version="6.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,10 +1,8 @@
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Providers;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
using Radzen;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
@ -25,7 +23,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddScoped<SiteState>();
|
||||
services.AddScoped<IInstallationService, InstallationService>();
|
||||
services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
|
||||
services.AddScoped<IThemeService, Oqtane.Services.ThemeService>();
|
||||
services.AddScoped<IThemeService, ThemeService>();
|
||||
services.AddScoped<IAliasService, AliasService>();
|
||||
services.AddScoped<ITenantService, TenantService>();
|
||||
services.AddScoped<ISiteService, SiteService>();
|
||||
@ -41,7 +39,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddScoped<ILogService, LogService>();
|
||||
services.AddScoped<IJobService, JobService>();
|
||||
services.AddScoped<IJobLogService, JobLogService>();
|
||||
services.AddScoped<INotificationService, Oqtane.Services.NotificationService>();
|
||||
services.AddScoped<INotificationService, NotificationService>();
|
||||
services.AddScoped<IFolderService, FolderService>();
|
||||
services.AddScoped<IFileService, FileService>();
|
||||
services.AddScoped<ISiteTemplateService, SiteTemplateService>();
|
||||
@ -55,18 +53,12 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddScoped<ISyncService, SyncService>();
|
||||
services.AddScoped<ILocalizationCookieService, LocalizationCookieService>();
|
||||
services.AddScoped<ICookieConsentService, CookieConsentService>();
|
||||
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
||||
services.AddScoped<IOutputCacheService, OutputCacheService>();
|
||||
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
||||
|
||||
// providers
|
||||
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();
|
||||
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.TextAreaTextEditor>();
|
||||
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.RadzenTextEditor>();
|
||||
|
||||
services.AddRadzenComponents();
|
||||
|
||||
var localizer = services.BuildServiceProvider().GetService<IStringLocalizer<Oqtane.Modules.Controls.RadzenTextEditor>>();
|
||||
Oqtane.Modules.Controls.RadzenEditorDefinitions.Localizer = localizer;
|
||||
|
||||
return services;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="mx-auto text-center">
|
||||
<img src="installer-logo.png" />
|
||||
<img src="oqtane-black.png" />
|
||||
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET @Environment.Version.Major)</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -182,7 +182,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
_databaseName = Constants.DefaultDBName;
|
||||
_databaseName = "LocalDB";
|
||||
}
|
||||
LoadDatabaseConfigComponent();
|
||||
|
||||
@ -269,8 +269,8 @@
|
||||
SiteName = Constants.DefaultSite,
|
||||
Register = _register,
|
||||
SiteTemplate = _template,
|
||||
RenderMode = "", // provided by appsettings.json
|
||||
Runtime = "" // provided by appsettings.json
|
||||
RenderMode = RenderModes.Static,
|
||||
Runtime = Runtimes.Server
|
||||
};
|
||||
|
||||
var installation = await InstallationService.Install(config);
|
||||
|
@ -56,7 +56,7 @@
|
||||
<input id="starting" type="date" class="form-control" @bind="@_startDate" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<input id="starting" type="time" class="form-control" @bind="@_startTime" placeholder="hh:mm" required="@(_startDate.HasValue)" />
|
||||
<input id="starting" type="time" class="form-control" placeholder="hh:mm" @bind="@_startTime" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -69,7 +69,7 @@
|
||||
<input id="ending" type="date" class="form-control" @bind="@_endDate" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" required="@(_endDate.HasValue)" />
|
||||
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -82,7 +82,7 @@
|
||||
<input id="next" type="date" class="form-control" @bind="@_nextDate" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" required="@(_nextDate.HasValue)" />
|
||||
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -176,18 +176,10 @@
|
||||
{
|
||||
job.Interval = int.Parse(_interval);
|
||||
}
|
||||
job.StartDate = _startDate.HasValue && _startTime.HasValue
|
||||
? LocalToUtc(_startDate.GetValueOrDefault().Date.Add(_startTime.GetValueOrDefault().TimeOfDay))
|
||||
: null;
|
||||
|
||||
job.EndDate = _endDate.HasValue && _endTime.HasValue
|
||||
? LocalToUtc(_endDate.GetValueOrDefault().Date.Add(_endTime.GetValueOrDefault().TimeOfDay))
|
||||
: null;
|
||||
|
||||
job.NextExecution = _nextDate.HasValue && _nextTime.HasValue
|
||||
? LocalToUtc(_nextDate.GetValueOrDefault().Date.Add(_nextTime.GetValueOrDefault().TimeOfDay))
|
||||
: null;
|
||||
job.RetentionHistory = int.Parse(_retentionHistory);
|
||||
job.StartDate = LocalToUtc(_startDate.Value.Date.Add(_startTime.Value.TimeOfDay));
|
||||
job.EndDate = LocalToUtc(_endDate.Value.Date.Add(_endTime.Value.TimeOfDay));
|
||||
job.RetentionHistory = int.Parse(_retentionHistory);
|
||||
job.NextExecution = LocalToUtc(_nextDate.Value.Date.Add(_nextTime.Value.TimeOfDay));
|
||||
|
||||
try
|
||||
{
|
||||
@ -206,4 +198,5 @@
|
||||
AddModuleMessage(Localizer["Message.Required.JobInfo"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -116,19 +116,11 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
Job _job = await JobService.GetJobAsync(jobId);
|
||||
if (!_job.IsEnabled)
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Job.Disabled"], MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
await JobService.StartJobAsync(jobId);
|
||||
await logger.LogInformation("Job Started {JobId}", jobId);
|
||||
AddModuleMessage(Localizer["Message.Job.Start"], MessageType.Success);
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
await JobService.StartJobAsync(jobId);
|
||||
await logger.LogInformation("Job Started {JobId}", jobId);
|
||||
AddModuleMessage(Localizer["Message.Job.Start"], MessageType.Success);
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -21,7 +21,9 @@ else
|
||||
@if (_allowexternallogin)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick="ExternalLogin">@Localizer["Use"] @PageState.Site.Settings["ExternalLogin:ProviderName"]</button>
|
||||
<br /><br />
|
||||
<br />
|
||||
|
||||
<br />
|
||||
}
|
||||
@if (_allowsitelogin)
|
||||
{
|
||||
@ -47,11 +49,15 @@ else
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" @onclick="Login">@SharedLocalizer["Login"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||
<br /><br />
|
||||
<br />
|
||||
|
||||
<br />
|
||||
<button type="button" class="btn btn-secondary" @onclick="Forgot">@Localizer["ForgotPassword"]</button>
|
||||
@if (PageState.Site.AllowRegistration)
|
||||
{
|
||||
<br /><br />
|
||||
<br />
|
||||
|
||||
<br />
|
||||
<NavLink href="@NavigateUrl("register")">@Localizer["Register"]</NavLink>
|
||||
}
|
||||
}
|
||||
|
@ -310,6 +310,6 @@
|
||||
|
||||
private void OnUpload()
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Success.Module.Upload"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Module.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ else
|
||||
<div class="row mb-3 align-items-center">
|
||||
<div class="col-sm-6">
|
||||
<ActionLink Action="Add" Text="Install Module" ResourceKey="InstallModule" />
|
||||
<ActionLink Action="Create" Text="Create Module" ResourceKey="CreateModule" Class="btn btn-secondary ms-1" />
|
||||
<button type="button" class="btn btn-secondary ms-1" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
||||
<ActionLink Action="Create" Text="Create Module" ResourceKey="CreateModule" Class="btn btn-secondary ps-2" />
|
||||
<button type="button" class="btn btn-secondary pw-2" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
||||
|
@ -56,7 +56,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="options" HelpText="A comma delimited list of options. Options can contain a key and value if they are seperated by a colon (ie. key:value). You can also dynamically load your options from custom Settings (ie. 'EntityName:Countries')." ResourceKey="Options">Options: </Label>
|
||||
<Label Class="col-sm-3" For="options" HelpText="A comma delimited list of options the user can select from" ResourceKey="Options">Options: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="options" class="form-control" @bind="@_options" maxlength="2000" />
|
||||
</div>
|
||||
|
@ -3,10 +3,10 @@
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserService UserService
|
||||
@inject ITimeZoneService TimeZoneService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
@inject ISettingService SettingService
|
||||
@inject ITimeZoneService TimeZoneService
|
||||
|
||||
@if (_initialized)
|
||||
{
|
||||
@ -115,7 +115,7 @@
|
||||
{
|
||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
|
||||
_timezones = TimeZoneService.GetTimeZones();
|
||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||
_timezoneid = PageState.Site.TimeZoneId;
|
||||
_initialized = true;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@
|
||||
<Row>
|
||||
<div class="search-item mb-2">
|
||||
<h4 class="mb-1"><a href="@context.Url">@context.Title</a></h4>
|
||||
<p class="mb-0 text-body-secondary">@((MarkupString)context.Snippet)</p>
|
||||
<p class="mb-0 text-muted">@((MarkupString)context.Snippet)</p>
|
||||
</div>
|
||||
</Row>
|
||||
</Pager>
|
||||
|
@ -1,226 +0,0 @@
|
||||
@namespace Oqtane.Modules.Admin.Settings
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="entityName" HelpText="Entity Name" ResourceKey="EntityName">Entity:</Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
@if (_entityNameElement == "input")
|
||||
{
|
||||
<input id="entityName" class="form-control" @bind="@_entityName" maxlength="256" required />
|
||||
}
|
||||
else
|
||||
{
|
||||
<select class="form-select custom-select" value="@_entityName" @onchange="(e => EntityNameChanged(e))">
|
||||
<option value="-"><@Localizer["Select Entity"]></option>
|
||||
@foreach (var entityName in _entityNames)
|
||||
{
|
||||
<option value="@entityName">@entityName</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" @onclick="@EntityNameClicked" tabindex="-1">@_entityNameTitle</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="entityId" HelpText="Entity Id" ResourceKey="EntityId">Id:</Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
@if (_entityIdElement == "input")
|
||||
{
|
||||
<input id="entityId" class="form-control" @bind="@_entityId" maxlength="256" required />
|
||||
}
|
||||
else
|
||||
{
|
||||
<select class="form-select custom-select" @bind="@_entityId">
|
||||
<option value="-"><@Localizer["Select Id"]></option>
|
||||
@foreach (var entityId in _entityIds)
|
||||
{
|
||||
<option value="@entityId">@entityId</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" @onclick="@EntityIdClicked" tabindex="-1">@_entityIdTitle</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="settingName" HelpText="Setting Name" ResourceKey="SettingName">Name:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="settingName" class="form-control" @bind="@_settingName" maxlength="256" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="settingValue" HelpText="Setting Value" ResourceKey="SettingValue">Value:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="SettingValue" class="form-control" @bind="@_settingValue" maxlength="256" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isPrivate" HelpText="Private" ResourceKey="IsPrivate">Private?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isPrivate" class="form-select" @bind="@_isPrivate">
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSetting">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
private string _entityName = "-";
|
||||
private List<string> _entityNames = new List<string>();
|
||||
private string _entityNameElement = "select";
|
||||
private string _entityNameTitle = "";
|
||||
private string _entityId = "-";
|
||||
private List<int> _entityIds = new List<int>();
|
||||
private string _entityIdElement = "select";
|
||||
private string _entityIdTitle = "";
|
||||
private string _settingName = "";
|
||||
private string _settingValue = "";
|
||||
private string _isPrivate = "True";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_entityNameTitle = Localizer["Input"];
|
||||
_entityIdTitle = Localizer["Input"];
|
||||
|
||||
// default entity names
|
||||
_entityNames.Add(EntityNames.Host);
|
||||
_entityNames.Add(EntityNames.Job);
|
||||
_entityNames.Add(EntityNames.ModuleDefinition);
|
||||
_entityNames.Add(EntityNames.Theme);
|
||||
_entityNames.Add(EntityNames.Tenant);
|
||||
_entityNames.Add(EntityNames.Site);
|
||||
_entityNames.Add(EntityNames.Role);
|
||||
_entityNames.Add(EntityNames.Page);
|
||||
_entityNames.Add(EntityNames.Module);
|
||||
_entityNames.Add(EntityNames.Folder);
|
||||
_entityNames.Add(EntityNames.User);
|
||||
_entityNames.Add(EntityNames.Visitor);
|
||||
|
||||
// custom entity names
|
||||
var entityNames = await SettingService.GetEntityNamesAsync();
|
||||
foreach (var entityName in entityNames)
|
||||
{
|
||||
if (!_entityNames.Contains(entityName))
|
||||
{
|
||||
_entityNames.Add(entityName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Setting {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadSetting"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void EntityNameClicked()
|
||||
{
|
||||
if (_entityNameElement == "select")
|
||||
{
|
||||
_entityName = "";
|
||||
_entityNameElement = "input";
|
||||
_entityNameTitle = Localizer["Select"];
|
||||
_entityId = "";
|
||||
_entityIdElement = "input";
|
||||
_entityIdTitle = Localizer["Select"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_entityName = "-";
|
||||
_entityNameElement = "select";
|
||||
_entityNameTitle = Localizer["Input"];
|
||||
}
|
||||
}
|
||||
|
||||
private void EntityIdClicked()
|
||||
{
|
||||
if (_entityIdElement == "select")
|
||||
{
|
||||
_entityId = "";
|
||||
_entityIdElement = "input";
|
||||
_entityIdTitle = Localizer["Select"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_entityId = "-";
|
||||
_entityIdElement = "select";
|
||||
_entityIdTitle = Localizer["Input"];
|
||||
}
|
||||
}
|
||||
|
||||
private async void EntityNameChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_entityName = e.Value.ToString();
|
||||
_entityId = "-";
|
||||
_entityIdElement = "select";
|
||||
_entityIdTitle = Localizer["Input"];
|
||||
if (_entityName != "-")
|
||||
{
|
||||
_entityIds = await SettingService.GetEntityIdsAsync(_entityName);
|
||||
}
|
||||
else
|
||||
{
|
||||
_entityIds = new List<int>();
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On EntityNameChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSetting()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form) && _entityName != "-" && int.TryParse(_entityId, out int entityId))
|
||||
{
|
||||
var setting = new Setting();
|
||||
setting.EntityName = _entityName;
|
||||
setting.EntityId = entityId;
|
||||
setting.SettingName = _settingName;
|
||||
setting.SettingValue = _settingValue;
|
||||
setting.IsPrivate = (bool.Parse(_isPrivate));
|
||||
|
||||
try
|
||||
{
|
||||
setting = await SettingService.AddSettingAsync(setting);
|
||||
await logger.LogInformation("Setting Saved {Setting}", setting);
|
||||
NavigationManager.NavigateTo(PageState.ReturnUrl);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Setting {Setting} {Error}", setting, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSetting"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
@namespace Oqtane.Modules.Admin.Settings
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="entityName" HelpText="Entity Name" ResourceKey="EntityName">Entity:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="entityName" class="form-control" @bind="@_entityName" maxlength="256" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="entityId" HelpText="Entity Id" ResourceKey="EntityId">Id:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="entityId" class="form-control" @bind="@_entityId" maxlength="256" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="settingName" HelpText="Setting Name" ResourceKey="SettingName">Name:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="settingName" class="form-control" @bind="@_settingName" maxlength="256" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="settingValue" HelpText="Setting Value" ResourceKey="SettingValue">Value:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="SettingValue" class="form-control" @bind="@_settingValue" maxlength="256" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isPrivate" HelpText="Private" ResourceKey="IsPrivate">Private?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isPrivate" class="form-select" @bind="@_isPrivate">
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSetting">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
|
||||
<br /><br />
|
||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
private int _settingId;
|
||||
private string _entityName;
|
||||
private string _entityId;
|
||||
private string _settingName;
|
||||
private string _settingValue;
|
||||
private string _isPrivate;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_settingId = int.Parse(PageState.QueryString["id"]);
|
||||
_entityName = PageState.QueryString["entity"];
|
||||
|
||||
try
|
||||
{
|
||||
var setting = await SettingService.GetSettingAsync(_entityName, _settingId);
|
||||
if (setting != null)
|
||||
{
|
||||
_entityId = setting.EntityId.ToString();
|
||||
_settingName = setting.SettingName;
|
||||
_settingValue = setting.SettingValue;
|
||||
_isPrivate = setting.IsPrivate.ToString();
|
||||
_createdby = setting.CreatedBy;
|
||||
_createdon = setting.CreatedOn;
|
||||
_modifiedby = setting.ModifiedBy;
|
||||
_modifiedon = setting.ModifiedOn;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Setting {SettingId} {Error}", _settingId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadSetting"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSetting()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
var setting = await SettingService.GetSettingAsync(_entityName, _settingId);
|
||||
setting.SettingValue = _settingValue;
|
||||
setting.IsPrivate = (_isPrivate != null && Boolean.Parse(_isPrivate));
|
||||
|
||||
try
|
||||
{
|
||||
setting = await SettingService.UpdateSettingAsync(setting);
|
||||
await logger.LogInformation("Setting Saved {Setting}", setting);
|
||||
NavigationManager.NavigateTo(PageState.ReturnUrl);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Setting {Setting} {Error}", setting, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSetting"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
@namespace Oqtane.Modules.Admin.Settings
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<ImportSettings> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="settings" HelpText="Provide settings in comma delimited format using the column template specified" ResourceKey="Settings">Settings:</Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="settings" class="form-control" @bind="@_settings" rows="5" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="Import">@Localizer["Import"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private string _settings = "Entity,Id,Name,Value,Private\n";
|
||||
|
||||
public override string Title => "Import Settings";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
private async Task Import()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_settings))
|
||||
{
|
||||
ShowProgressIndicator();
|
||||
var result = await SettingService.ImportSettingsAsync(new Result { Message = _settings });
|
||||
if (result.Success)
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Import.Success"], MessageType.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Import.Failure"], MessageType.Error);
|
||||
}
|
||||
HideProgressIndicator();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Import.Validation"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Importing Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Import"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
@namespace Oqtane.Modules.Admin.Settings
|
||||
@inherits ModuleBase
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-4">
|
||||
<ActionLink Action="Add" Text="Add Setting" Security="SecurityAccessLevel.Host" ResourceKey="AddSetting" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_entityName, _entityId)))" />
|
||||
<ActionLink Action="ImportSettings" Text="Import" Class="btn btn-secondary ms-1" Security="SecurityAccessLevel.Host" ResourceKey="ImportSettings" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_entityName, _entityId)))" />
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-select custom-select" value="@_entityName" @onchange="(e => EntityNameChanged(e))">
|
||||
<option value="-"><@Localizer["Select Entity"]></option>
|
||||
@foreach (var entityName in _entityNames)
|
||||
{
|
||||
<option value="@entityName">@entityName</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-select custom-select" value="@_entityId" @onchange="(e => EntityIdChanged(e))">
|
||||
<option value="-"><@Localizer["Select Id"]></option>
|
||||
@foreach (var entityId in _entityIds)
|
||||
{
|
||||
<option value="@entityId">@entityId</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<Pager Items="@_settings" SearchProperties="SettingName,SettingValue">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Name"]</th>
|
||||
<th>@Localizer["Value"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"entity={context.EntityName}&id={context.SettingId}")" Security="SecurityAccessLevel.Host" ResourceKey="EditSetting" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_entityName, _entityId)))" /></td>
|
||||
<td><ActionDialog Header="Delete Setting" Message="@string.Format(Localizer["Confirm.DeleteSetting"], context.SettingName)" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteSetting(context))" ResourceKey="DeleteSetting" /></td>
|
||||
<td>@context.SettingName</td>
|
||||
<td>@context.SettingValue</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
|
||||
@code {
|
||||
private string _entityName = "-";
|
||||
private List<string> _entityNames = new List<string>();
|
||||
private string _entityId = "-";
|
||||
private List<int> _entityIds = new List<int>();
|
||||
private List<Setting> _settings = new List<Setting>();
|
||||
|
||||
public override string UrlParametersTemplate => "/{entityname}/{entityid}";
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_entityNames = await SettingService.GetEntityNamesAsync();
|
||||
|
||||
if (UrlParameters.ContainsKey("entityname"))
|
||||
{
|
||||
_entityName = UrlParameters["entityname"];
|
||||
await GetEntityIds();
|
||||
}
|
||||
if (UrlParameters.ContainsKey("entityid"))
|
||||
{
|
||||
_entityId = UrlParameters["entityid"];
|
||||
await GetSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetEntityIds()
|
||||
{
|
||||
if (_entityName != "-")
|
||||
{
|
||||
_entityIds = await SettingService.GetEntityIdsAsync(_entityName);
|
||||
}
|
||||
else
|
||||
{
|
||||
_entityIds = new List<int>();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetSettings()
|
||||
{
|
||||
if (_entityName != "-" && _entityId != "-")
|
||||
{
|
||||
_settings = await SettingService.GetSettingsAsync(_entityName, int.Parse(_entityId), "");
|
||||
_settings = _settings.OrderBy(item => item.SettingName).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_settings = new List<Setting>();
|
||||
}
|
||||
}
|
||||
|
||||
private async void EntityNameChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_entityName = e.Value.ToString();
|
||||
_entityId = "-";
|
||||
await GetEntityIds();
|
||||
await GetSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On EntityNameChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private async void EntityIdChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_entityId = e.Value.ToString();
|
||||
await GetSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On EntityIdChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteSetting(Setting setting)
|
||||
{
|
||||
try
|
||||
{
|
||||
await SettingService.DeleteSettingAsync(setting.EntityName, setting.EntityId, setting.SettingName);
|
||||
await logger.LogInformation("Setting Deleted {Setting}", setting);
|
||||
await GetSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Setting {Setting} {Error}", setting, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.DeleteSetting"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -54,18 +54,15 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Deleted? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Deleted? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="sitemap" HelpText="The site map url for this site which can be submitted to search engines for indexing. The sitemap is cached for 5 minutes and the cache can be manually cleared." ResourceKey="SiteMap">Site Map: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -197,128 +194,80 @@
|
||||
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpenabled" HelpText="Specify if SMTP is enabled for this site" ResourceKey="SmtpEnabled">Enabled? </Label>
|
||||
<div class="col-sm-3">
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<select id="smtpenabled" class="form-select" value="@_smtpenabled" @onchange="(e => SMTPEnabledChanged(e))">
|
||||
<strong>@Localizer["Smtp.Required.EnableNotificationJob"]</strong><br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="host" HelpText="Enter the host name of the SMTP server" ResourceKey="Host">Host: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="host" class="form-control" @bind="@_smtphost" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="port" HelpText="Enter the port number for the SMTP server. Please note this field is required if you provide a host name." ResourceKey="Port">Port: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="port" class="form-control" @bind="@_smtpport" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpssl" HelpText="Specify if SSL is required for your SMTP server" ResourceKey="UseSsl">SSL Enabled: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="smtpssl" class="form-select" @bind="@_smtpssl" >
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (_smtpenabled == "True" && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-3">
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<strong>@Localizer["Smtp.Required.EnableNotificationJob"]</strong><br />
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="username" HelpText="Enter the username for your SMTP account" ResourceKey="SmtpUsername">Username: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="username" class="form-control" @bind="@_smtpusername" autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="Enter the password for your SMTP account" ResourceKey="SmtpPassword">Password: </Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" autocomplete="off"/>
|
||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword" tabindex="-1">@_togglesmtppassword</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="host" HelpText="Enter the host name of the SMTP server" ResourceKey="Host">Host: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="host" class="form-control" @bind="@_smtphost" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="sender" HelpText="Enter the email which emails will be sent from. Please note that this email address may need to be authorized with the SMTP server." ResourceKey="SmtpSender">Email Sender: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="sender" class="form-control" @bind="@_smtpsender" />
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="port" HelpText="Enter the port number for the SMTP server. Please note this field is required if you provide a host name." ResourceKey="Port">Port: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="port" class="form-control" @bind="@_smtpport" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="relay" HelpText="Only specify this option if you have properly configured an SMTP Relay Service to route your outgoing mail. This option will send notifications from the user's email rather than from the Email Sender specified above." ResourceKey="SmtpRelay">Relay Configured? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="relay" class="form-select" @bind="@_smtprelay" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpssl" HelpText="Specify the type of SSL connection for your SMTP server" ResourceKey="SmtpSSL">SSL Options: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="smtpssl" class="form-select" @bind="@_smtpssl">
|
||||
<option value="None">@Localizer["None"]</option>
|
||||
<option value="Auto">@Localizer["Auto"]</option>
|
||||
<option value="StartTls">@Localizer["StartTls"]</option>
|
||||
<option value="SslOnConnect">@Localizer["SslOnConnect"]</option>
|
||||
<option value="StartTlsWhenAvailable">@Localizer["StartTlsWhenAvailable"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpenabled" HelpText="Specify if SMTP is enabled for this site" ResourceKey="SMTPEnabled">Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="smtpenabled" class="form-select" @bind="@_smtpenabled">
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpauthentication" HelpText="Specify the SMTP authentication type" ResourceKey="SMTPAuthentication">Authentication: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="smtpauthentication" class="form-select" value="@_smtpauthentication" @onchange="(e => SMTPAuthenticationChanged(e))">
|
||||
<option value="Basic">@Localizer["Basic"]</option>
|
||||
<option value="OAuth2">@Localizer["OAuth2"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
|
||||
</div>
|
||||
@if (_smtpauthentication == "Basic")
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="username" HelpText="Enter the username for your SMTP account" ResourceKey="SmtpUsername">Username: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="username" class="form-control" @bind="@_smtpusername" autocomplete="off" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="Enter the password for your SMTP account" ResourceKey="SmtpPassword">Password: </Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" autocomplete="off" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword" tabindex="-1">@_togglesmtppassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="relay" HelpText="Only specify this option if you have properly configured an SMTP Relay Service to route your outgoing mail. This option will send notifications from the user's email rather than from the Email Sender specified below." ResourceKey="SmtpRelay">Relay Configured? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="relay" class="form-select" @bind="@_smtprelay" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpauthority" HelpText="The Authority Url for the SMTP provider" ResourceKey="SmtpAuthority">Authority Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="smtpauthority" class="form-control" @bind="@_smtpauthority" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpclientid" HelpText="The Client ID for the SMTP provider" ResourceKey="SmtpClientID">Client ID:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="smtpclientid" class="form-control" @bind="@_smtpclientid" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpclientsecret" HelpText="The Client Secret for the SMTP provider" ResourceKey="SmtpClientSecret">Client Secret:</Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input type="@_smtpclientsecrettype" id="smtpclientsecret" class="form-control" @bind="@_smtpclientsecret" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleSmtpClientSecret">@_togglesmtpclientsecret</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="smtpscopes" HelpText="A list of Scopes for the SMTP provider (separated by commas)" ResourceKey="SmtpScopes">Scopes:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="smtpscopes" class="form-control" @bind="@_smtpscopes" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="sender" HelpText="Enter the email address which emails will be sent from. Please note that this email address usually needs to be authorized with the SMTP provider." ResourceKey="SmtpSender">Email Sender: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="sender" class="form-control" @bind="@_smtpsender" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary" @onclick="SendEmail">@Localizer["Smtp.TestConfig"]</button>
|
||||
<br /><br />
|
||||
}
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary" @onclick="SendEmail">@Localizer["Smtp.TestConfig"]</button>
|
||||
<br /><br />
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="PWA" Heading="Progressive Web Application Settings" ResourceKey="PWASettings">
|
||||
@ -506,23 +455,16 @@
|
||||
private string _headcontent = string.Empty;
|
||||
private string _bodycontent = string.Empty;
|
||||
|
||||
private string _smtpenabled = "False";
|
||||
private string _smtpauthentication = "Basic";
|
||||
private string _smtphost = string.Empty;
|
||||
private string _smtpport = string.Empty;
|
||||
private string _smtpssl = "Auto";
|
||||
private string _smtpssl = "False";
|
||||
private string _smtpusername = string.Empty;
|
||||
private string _smtppassword = string.Empty;
|
||||
private string _smtppasswordtype = "password";
|
||||
private string _togglesmtppassword = string.Empty;
|
||||
private string _smtpauthority = string.Empty;
|
||||
private string _smtpclientid = string.Empty;
|
||||
private string _smtpclientsecret = string.Empty;
|
||||
private string _smtpclientsecrettype = "password";
|
||||
private string _togglesmtpclientsecret = string.Empty;
|
||||
private string _smtpscopes = string.Empty;
|
||||
private string _smtpsender = string.Empty;
|
||||
private string _smtprelay = "False";
|
||||
private string _smtpenabled = "True";
|
||||
private int _retention = 30;
|
||||
|
||||
private string _pwaisenabled;
|
||||
@ -566,7 +508,7 @@
|
||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
_timezones = TimeZoneService.GetTimeZones();
|
||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
|
||||
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||
@ -614,27 +556,16 @@
|
||||
_bodycontent = site.BodyContent;
|
||||
|
||||
// SMTP
|
||||
_smtpenabled = SettingService.GetSetting(settings, "SMTPEnabled", "False");
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "Auto");
|
||||
if (_smtpssl == "True") _smtpssl = "SslOnConnect";
|
||||
if (_smtpssl == "False") _smtpssl = "StartTlsWhenAvailable";
|
||||
_smtpauthentication = SettingService.GetSetting(settings, "SMTPAuthentication", "Basic");
|
||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
_smtpauthority = SettingService.GetSetting(settings, "SMTPAuthority", string.Empty);
|
||||
_smtpclientid = SettingService.GetSetting(settings, "SMTPClientId", string.Empty);
|
||||
_smtpclientsecret = SettingService.GetSetting(settings, "SMTPClientSecret", string.Empty);
|
||||
_togglesmtpclientsecret = SharedLocalizer["ShowPassword"];
|
||||
_smtpscopes = SettingService.GetSetting(settings, "SMTPScopes", string.Empty);
|
||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||
_smtprelay = SettingService.GetSetting(settings, "SMTPRelay", "False");
|
||||
_retention = int.Parse(SettingService.GetSetting(settings, "NotificationRetention", "30"));
|
||||
}
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||
_smtprelay = SettingService.GetSetting(settings, "SMTPRelay", "False");
|
||||
_smtpenabled = SettingService.GetSetting(settings, "SMTPEnabled", "True");
|
||||
_retention = int.Parse(SettingService.GetSetting(settings, "NotificationRetention", "30"));
|
||||
|
||||
// PWA
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
@ -665,8 +596,7 @@
|
||||
if (tenant != null)
|
||||
{
|
||||
_tenant = tenant.Name;
|
||||
// hack - there are 3 providers with SqlServerDatabase DBTypes - so we are choosing the last one in alphabetical order
|
||||
_database = _databases.Where(item => item.DBType == tenant.DBType).OrderBy(item => item.Name).Last()?.Name;
|
||||
_database = _databases.Find(item => item.DBType == tenant.DBType && item.Name != "LocalDB")?.Name;
|
||||
_connectionstring = tenant.DBConnectionString;
|
||||
}
|
||||
}
|
||||
@ -812,23 +742,16 @@
|
||||
|
||||
// SMTP
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPAuthentication", _smtpauthentication, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPAuthority", _smtpauthority, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPClientId", _smtpclientid, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPClientSecret", _smtpclientsecret, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPScopes", _smtpscopes, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
||||
}
|
||||
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
||||
|
||||
//cookie consent
|
||||
settings = SettingService.SetSetting(settings, "CookieConsent", _cookieconsent);
|
||||
@ -836,7 +759,6 @@
|
||||
// functionality
|
||||
settings = SettingService.SetSetting(settings, "TextEditor", _textEditor);
|
||||
|
||||
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||
|
||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||
@ -891,46 +813,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void SMTPAuthenticationChanged(ChangeEventArgs e)
|
||||
{
|
||||
_smtpauthentication = (string)e.Value;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void SMTPEnabledChanged(ChangeEventArgs e)
|
||||
{
|
||||
_smtpenabled = (string)e.Value;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void ToggleSMTPPassword()
|
||||
{
|
||||
if (_smtppasswordtype == "password")
|
||||
{
|
||||
_smtppasswordtype = "text";
|
||||
_togglesmtppassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_smtppasswordtype = "password";
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleSmtpClientSecret()
|
||||
{
|
||||
if (_smtpclientsecrettype == "password")
|
||||
{
|
||||
_smtpclientsecrettype = "text";
|
||||
_togglesmtpclientsecret = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_smtpclientsecrettype = "password";
|
||||
_togglesmtpclientsecret = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendEmail()
|
||||
{
|
||||
if (_smtphost != "" && _smtpport != "" && _smtpsender != "")
|
||||
@ -941,13 +823,8 @@
|
||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPAuthentication", _smtpauthentication, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPAuthority", _smtpauthority, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPClientId", _smtpclientid, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPClientSecret", _smtpclientsecret, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPScopes", _smtpscopes, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
await logger.LogInformation("Site SMTP Settings Saved");
|
||||
@ -968,6 +845,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleSMTPPassword()
|
||||
{
|
||||
if (_smtppasswordtype == "password")
|
||||
{
|
||||
_smtppasswordtype = "text";
|
||||
_togglesmtppassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_smtppasswordtype = "password";
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetAliases()
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
|
@ -118,42 +118,42 @@ else
|
||||
<Label Class="col-sm-3" For="databaseType" HelpText="Select the database type" ResourceKey="DatabaseType">Type: </Label>
|
||||
<div class="col-sm-9">
|
||||
@if (_databases != null)
|
||||
{
|
||||
<div class="input-group">
|
||||
<select id="databaseType" class="form-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))" required>
|
||||
@foreach (var database in _databases)
|
||||
{
|
||||
<option value="@database.Name">@Localizer[@database.Name]</option>
|
||||
}
|
||||
</select>
|
||||
@if (!_showConnectionString)
|
||||
{
|
||||
<button type="button" class="btn btn-secondary" @onclick="ToggleConnectionString">@Localizer["EnterConnectionString"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-secondary" @onclick="ToggleConnectionString">@Localizer["EnterConnectionParameters"]</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
{
|
||||
<div class="input-group">
|
||||
<select id="databaseType" class="form-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))" required>
|
||||
@foreach (var database in _databases)
|
||||
{
|
||||
<option value="@database.Name">@Localizer[@database.Name]</option>
|
||||
}
|
||||
</select>
|
||||
@if (!_showConnectionString)
|
||||
{
|
||||
<button type="button" class="btn btn-secondary" @onclick="ToggleConnectionString">@Localizer["EnterConnectionString"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-secondary" @onclick="ToggleConnectionString">@Localizer["EnterConnectionParameters"]</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@if (!_showConnectionString)
|
||||
{
|
||||
if (_databaseConfigType != null)
|
||||
{
|
||||
@DatabaseConfigComponent
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">Settings:</Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (!_showConnectionString)
|
||||
{
|
||||
if (_databaseConfigType != null)
|
||||
{
|
||||
@DatabaseConfigComponent
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">Settings:</Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="hostUsername" HelpText="Enter the username of an existing host user" ResourceKey="HostUsername">Host Username:</Label>
|
||||
<div class="col-sm-9">
|
||||
@ -237,7 +237,7 @@ else
|
||||
}
|
||||
else
|
||||
{
|
||||
_databaseName = Constants.DefaultDBName;
|
||||
_databaseName = "LocalDB";
|
||||
}
|
||||
LoadDatabaseConfigComponent();
|
||||
}
|
||||
@ -390,8 +390,6 @@ else
|
||||
config.DatabaseType = tenant.DBType;
|
||||
config.ConnectionString = tenant.DBConnectionString;
|
||||
config.IsNewTenant = false;
|
||||
config.HostEmail = PageState.User.Email;
|
||||
config.HostName = PageState.User.DisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,7 +403,6 @@ else
|
||||
config.SiteTemplate = _sitetemplatetype;
|
||||
config.RenderMode = _rendermode;
|
||||
config.Runtime = _runtime;
|
||||
config.Register = false;
|
||||
|
||||
ShowProgressIndicator();
|
||||
|
||||
|
@ -200,8 +200,7 @@ else
|
||||
if (tenant != null)
|
||||
{
|
||||
_tenant = tenant.Name;
|
||||
// hack - there are 3 providers with SqlServerDatabase DBTypes - so we are choosing the last one in alphabetical order
|
||||
_databasetype = _databases.Where(item => item.DBType == tenant.DBType).OrderBy(item => item.Name).Last()?.Name;
|
||||
_databasetype = _databases.FirstOrDefault(item => item.DBType == tenant.DBType && item.Name != "LocalDB").Name;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -212,7 +211,7 @@ else
|
||||
}
|
||||
else
|
||||
{
|
||||
_databasetype = Constants.DefaultDBName;
|
||||
_databasetype = "LocalDB";
|
||||
}
|
||||
_showConnectionString = false;
|
||||
LoadDatabaseConfigComponent();
|
||||
|
@ -310,6 +310,6 @@
|
||||
|
||||
private void OnUpload()
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Upload"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,12 @@
|
||||
else
|
||||
{
|
||||
<ActionLink Action="Add" Text="Install Theme" ResourceKey="InstallTheme" />
|
||||
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" Class="btn btn-secondary ms-1" />
|
||||
<button type="button" class="btn btn-secondary ms-1" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
||||
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" Class="btn btn-secondary ps-2" />
|
||||
<button type="button" class="btn btn-secondary pw-2" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
||||
|
||||
<Pager Items="@_themes">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
@ -37,6 +38,7 @@ else
|
||||
<ActionDialog Header="Delete Theme" Message="@string.Format(Localizer["Confirm.Theme.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteTheme(context))" ResourceKey="DeleteTheme" />
|
||||
}
|
||||
</td>
|
||||
<td><NavLink class="btn btn-secondary" href="@NavigateUrl("admin/site")">@Localizer["Assign"]</NavLink></td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Version</td>
|
||||
<td>
|
||||
|
@ -124,19 +124,15 @@
|
||||
@if (!string.IsNullOrEmpty(p.Autocomplete))
|
||||
{
|
||||
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete">
|
||||
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var values = option.Split(':');
|
||||
var name = values[0];
|
||||
var value = values.Length > 1 ? values[1] : values[0];
|
||||
@if (GetProfileValue(p.Name, "") == name || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == name))
|
||||
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
|
||||
{
|
||||
<option value="@name" selected>@value</option>
|
||||
<option value="@option" selected>@option</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@name">@value</option>
|
||||
<option value="@option">@option</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
@ -144,19 +140,15 @@
|
||||
else
|
||||
{
|
||||
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
|
||||
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var values = option.Split(':');
|
||||
var name = values[0];
|
||||
var value = values.Length > 1 ? values[1] : values[0];
|
||||
@if (GetProfileValue(p.Name, "") == name || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == name))
|
||||
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
|
||||
{
|
||||
<option value="@name" selected>@value</option>
|
||||
<option value="@option" selected>@option</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@name">@value</option>
|
||||
<option value="@option">@option</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
@ -375,6 +367,7 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<Models.TimeZone> _timezones;
|
||||
private bool _initialized = false;
|
||||
private string _passwordrequirements;
|
||||
private string _username = string.Empty;
|
||||
@ -388,7 +381,6 @@
|
||||
private string _displayname = string.Empty;
|
||||
private FileManager _filemanager;
|
||||
private int _folderid = -1;
|
||||
private List<Models.TimeZone> _timezones;
|
||||
private string _timezoneid = string.Empty;
|
||||
private int _photofileid = -1;
|
||||
private File _photo = null;
|
||||
@ -412,15 +404,7 @@
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
_allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true");
|
||||
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||
foreach (var profile in _profiles)
|
||||
{
|
||||
if (profile.Options.ToLower().StartsWith("entityname:"))
|
||||
{
|
||||
var options = await SettingService.GetSettingsAsync(profile.Options.Substring(11), -1);
|
||||
profile.Options = string.Join(",", options.Select(kvp => $"{kvp.Key}:{kvp.Value}"));
|
||||
}
|
||||
}
|
||||
_timezones = TimeZoneService.GetTimeZones();
|
||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||
|
||||
if (PageState.User != null)
|
||||
{
|
||||
@ -430,6 +414,11 @@
|
||||
_displayname = PageState.User.DisplayName;
|
||||
_timezoneid = PageState.User.TimeZoneId;
|
||||
|
||||
if (string.IsNullOrEmpty(_email))
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.User.NoEmail"], MessageType.Warning);
|
||||
}
|
||||
|
||||
// get user folder
|
||||
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
||||
if (folder != null)
|
||||
|
@ -28,15 +28,6 @@
|
||||
<input id="email" class="form-control" @bind="@_email" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="confirmed" HelpText="Indicates if the user's email is verified" ResourceKey="Confirmed">Verified?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="confirmed" class="form-select" @bind="@_confirmed">
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
|
||||
<div class="col-sm-9">
|
||||
@ -86,19 +77,15 @@
|
||||
@if (!string.IsNullOrEmpty(p.Options))
|
||||
{
|
||||
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
|
||||
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var values = option.Split(':');
|
||||
var name = values[0];
|
||||
var value = values.Length > 1 ? values[1] : values[0];
|
||||
@if (GetProfileValue(p.Name, "") == name || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == name))
|
||||
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
|
||||
{
|
||||
<option value="@name" selected>@value</option>
|
||||
<option value="@option" selected>@option</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@name">@value</option>
|
||||
<option value="@option">@option</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
@ -133,7 +120,6 @@
|
||||
private bool _initialized = false;
|
||||
private string _username = string.Empty;
|
||||
private string _email = string.Empty;
|
||||
private string _confirmed = "True";
|
||||
private string _displayname = string.Empty;
|
||||
private string _timezoneid = string.Empty;
|
||||
private string _notify = "True";
|
||||
@ -147,16 +133,8 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
_timezones = TimeZoneService.GetTimeZones();
|
||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||
foreach (var profile in _profiles)
|
||||
{
|
||||
if (profile.Options.ToLower().StartsWith("entityname:"))
|
||||
{
|
||||
var options = await SettingService.GetSettingsAsync(profile.Options.Substring(11), -1);
|
||||
profile.Options = string.Join(",", options.Select(kvp => $"{kvp.Key}:{kvp.Value}"));
|
||||
}
|
||||
}
|
||||
_settings = new Dictionary<string, string>();
|
||||
_timezoneid = PageState.Site.TimeZoneId;
|
||||
_initialized = true;
|
||||
@ -191,7 +169,6 @@
|
||||
user.Username = _username;
|
||||
user.Password = ""; // will be auto generated
|
||||
user.Email = _email;
|
||||
user.EmailConfirmed = bool.Parse(_confirmed);
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
||||
user.TimeZoneId = _timezoneid;
|
||||
user.PhotoFileId = null;
|
||||
|
@ -48,7 +48,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="confirmed" HelpText="Indicates if the user's email is verified" ResourceKey="Confirmed">Verified?</Label>
|
||||
<Label Class="col-sm-3" For="confirmed" HelpText="Indicates if the user's email is verified" ResourceKey="Confirmed">Confirmed?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="confirmed" class="form-select" @bind="@_confirmed">
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
@ -119,19 +119,15 @@
|
||||
@if (!string.IsNullOrEmpty(p.Options))
|
||||
{
|
||||
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
|
||||
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var values = option.Split(':');
|
||||
var name = values[0];
|
||||
var value = values.Length > 1 ? values[1] : values[0];
|
||||
@if (GetProfileValue(p.Name, "") == name || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == name))
|
||||
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
|
||||
{
|
||||
<option value="@name" selected>@value</option>
|
||||
<option value="@option" selected>@option</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@name">@value</option>
|
||||
<option value="@option">@option</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
@ -157,13 +153,13 @@
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin) && PageState.Runtime != Shared.Runtime.Hybrid && !_ishost && _isdeleted != "True")
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin) && PageState.Runtime != Shared.Runtime.Hybrid && !_ishost)
|
||||
{
|
||||
<button type="button" class="btn btn-primary ms-1" @onclick="ImpersonateUser">@Localizer["Impersonate"]</button>
|
||||
}
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && _isdeleted == "True")
|
||||
{
|
||||
<ActionDialog Header="Delete User" Message="Are You Sure You Wish To Permanently Delete This User?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger ms-1" OnClick="@(async () => await DeleteUser())" ResourceKey="DeleteUser" />
|
||||
<ActionDialog Header="Delete User" Message="Are You Sure You Wish To Permanently Delete This User?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteUser())" ResourceKey="DeleteUser" />
|
||||
}
|
||||
<br /><br />
|
||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
||||
@ -208,15 +204,7 @@
|
||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
_profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
||||
foreach (var profile in _profiles)
|
||||
{
|
||||
if (profile.Options.ToLower().StartsWith("entityname:"))
|
||||
{
|
||||
var options = await SettingService.GetSettingsAsync(profile.Options.Substring(11), -1);
|
||||
profile.Options = string.Join(",", options.Select(kvp => $"{kvp.Key}:{kvp.Value}"));
|
||||
}
|
||||
}
|
||||
_timezones = TimeZoneService.GetTimeZones();
|
||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||
|
||||
if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int UserId))
|
||||
{
|
||||
|
@ -17,21 +17,8 @@ else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Users" Heading="Users" ResourceKey="Users">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-6">
|
||||
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
||||
<ActionLink Text="Import Users" Class="btn btn-secondary ms-2" Action="Users" Security="SecurityAccessLevel.Admin" ResourceKey="ImportUsers" />
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<select id="deleted" class="form-select custom-select" value="@_deleted" @onchange="(e => DeletedChanged(e))">
|
||||
<option value="false">@Localizer["Active Users"]</option>
|
||||
<option value="true">@Localizer["Deleted Users"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
||||
<ActionLink Text="Import Users" Class="btn btn-secondary ms-2" Action="Users" Security="SecurityAccessLevel.Admin" ResourceKey="ImportUsers"/>
|
||||
|
||||
<Pager Items="@users" RowClass="align-middle" SearchProperties="User.Username,User.Email,User.DisplayName">
|
||||
<Header>
|
||||
@ -87,19 +74,10 @@ else
|
||||
<input id="profileurl" class="form-control" @bind="@_profileurl" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="requireconfirmedemail" HelpText="Do you want to require registered users to verify their email address before they are allowed to log in?" ResourceKey="RequireConfirmedEmail">Require Verified Email?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="requireconfirmedemail" class="form-select" @bind="@_requireconfirmedemail">
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="twofactor" HelpText="Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out." ResourceKey="TwoFactor">Two Factor Authentication?</Label>
|
||||
<Label Class="col-sm-3" For="twofactor" HelpText="Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out." ResourceKey="TwoFactor">Two Factor?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="twofactor" class="form-select" @bind="@_twofactor">
|
||||
<option value="false">@Localizer["Disabled"]</option>
|
||||
@ -114,12 +92,6 @@ else
|
||||
<input id="cookiename" class="form-control" @bind="@_cookiename" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="cookiedomain" HelpText="If you would like to share cookies across subdomains you will need to specify a root domain with a leading dot (ie. '.example.com')" ResourceKey="CookieDomain">Cookie Domain:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="cookiedomain" class="form-control" @bind="@_cookiedomain" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="cookieexpiration" HelpText="You can choose to use a custom authentication cookie expiration timespan for each site (e.g. '08:00:00' for 8 hours). The default is 14 days if not specified." ResourceKey="CookieExpiration">Cookie Expiration Timespan:</Label>
|
||||
<div class="col-sm-9">
|
||||
@ -320,15 +292,6 @@ else
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="requirenonce" HelpText="Specify if Nonce validation is required for the ID token (the default is true)" ResourceKey="RequireNonce">Require Nonce?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="requirenonce" class="form-select" @bind="@_requirenonce" required>
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="scopes" HelpText="A list of Scopes to request from the provider (separated by commas). If none are specified, standard Scopes will be used by default." ResourceKey="Scopes">Scopes:</Label>
|
||||
@ -523,15 +486,12 @@ else
|
||||
|
||||
@code {
|
||||
private List<UserRole> users;
|
||||
private string _deleted = "false";
|
||||
|
||||
private string _allowregistration;
|
||||
private string _registerurl;
|
||||
private string _profileurl;
|
||||
private string _requireconfirmedemail;
|
||||
private string _twofactor;
|
||||
private string _cookiename;
|
||||
private string _cookiedomain;
|
||||
private string _cookieexpiration;
|
||||
private string _alwaysremember;
|
||||
private string _logouteverywhere;
|
||||
@ -559,7 +519,6 @@ else
|
||||
private string _clientsecrettype = "password";
|
||||
private string _toggleclientsecret = string.Empty;
|
||||
private string _authresponsetype;
|
||||
private string _requirenonce;
|
||||
private string _scopes;
|
||||
private string _parameters;
|
||||
private string _pkce;
|
||||
@ -595,19 +554,17 @@ else
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadUsersAsync();
|
||||
await LoadUsersAsync(true);
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_allowregistration = PageState.Site.AllowRegistration.ToString().ToLower();
|
||||
_registerurl = SettingService.GetSetting(settings, "LoginOptions:RegisterUrl", "");
|
||||
_profileurl = SettingService.GetSetting(settings, "LoginOptions:ProfileUrl", "");
|
||||
_requireconfirmedemail = SettingService.GetSetting(settings, "LoginOptions:RequireConfirmedEmail", "true");
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_twofactor = SettingService.GetSetting(settings, "LoginOptions:TwoFactor", "false");
|
||||
_cookiename = SettingService.GetSetting(settings, "LoginOptions:CookieName", ".AspNetCore.Identity.Application");
|
||||
_cookiedomain = SettingService.GetSetting(settings, "LoginOptions:CookieDomain", "");
|
||||
_cookieexpiration = SettingService.GetSetting(settings, "LoginOptions:CookieExpiration", "");
|
||||
_alwaysremember = SettingService.GetSetting(settings, "LoginOptions:AlwaysRemember", "false");
|
||||
_logouteverywhere = SettingService.GetSetting(settings, "LoginOptions:LogoutEverywhere", "false");
|
||||
@ -647,7 +604,6 @@ else
|
||||
_clientsecret = SettingService.GetSetting(settings, "ExternalLogin:ClientSecret", "");
|
||||
_toggleclientsecret = SharedLocalizer["ShowPassword"];
|
||||
_authresponsetype = SettingService.GetSetting(settings, "ExternalLogin:AuthResponseType", "code");
|
||||
_requirenonce = SettingService.GetSetting(settings, "ExternalLogin:RequireNonce", "true");
|
||||
_scopes = SettingService.GetSetting(settings, "ExternalLogin:Scopes", "");
|
||||
_parameters = SettingService.GetSetting(settings, "ExternalLogin:Parameters", "");
|
||||
_pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false");
|
||||
@ -669,32 +625,20 @@ else
|
||||
_allowsitelogin = SettingService.GetSetting(settings, "LoginOptions:AllowSiteLogin", "true");
|
||||
}
|
||||
|
||||
private async Task LoadUsersAsync()
|
||||
private async Task LoadUsersAsync(bool load)
|
||||
{
|
||||
users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
if (load)
|
||||
{
|
||||
var hosts = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Host);
|
||||
users.AddRange(hosts);
|
||||
users = users.OrderBy(u => u.User.DisplayName).ToList();
|
||||
users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var hosts = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Host);
|
||||
users.AddRange(hosts);
|
||||
users = users.OrderBy(u => u.User.DisplayName).ToList();
|
||||
}
|
||||
}
|
||||
users = users.Where(item => item.User.IsDeleted == bool.Parse(_deleted)).ToList();
|
||||
}
|
||||
|
||||
private async void DeletedChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_deleted = e.Value.ToString();
|
||||
await LoadUsersAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On DeletedChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteUser(UserRole UserRole)
|
||||
{
|
||||
try
|
||||
@ -717,7 +661,7 @@ else
|
||||
await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name);
|
||||
}
|
||||
AddModuleMessage(Localizer["Success.DeleteUser"], MessageType.Success);
|
||||
await LoadUsersAsync();
|
||||
await LoadUsersAsync(true);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -741,10 +685,8 @@ else
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:RegisterUrl", _registerurl, false);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:ProfileUrl", _profileurl, false);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:RequireConfirmedEmail", _requireconfirmedemail, false);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:TwoFactor", _twofactor, false);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:CookieName", _cookiename, true);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:CookieDomain", _cookiedomain, true);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:CookieExpiration", _cookieexpiration, true);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:AlwaysRemember", _alwaysremember, false);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:LogoutEverywhere", _logouteverywhere, false);
|
||||
@ -770,7 +712,6 @@ else
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:ClientId", _clientid, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:ClientSecret", _clientsecret, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:AuthResponseType", _authresponsetype, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:RequireNonce", _requirenonce, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Scopes", _scopes, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Parameters", _parameters, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:PKCE", _pkce, true);
|
||||
|
@ -52,7 +52,7 @@
|
||||
|
||||
if (CreatedOn != null)
|
||||
{
|
||||
_text += $" {Localizer["On"]} <b>{UtcToLocal(CreatedOn).Value.ToString(DateTimeFormat)}</b>";
|
||||
_text += $" {Localizer["On"]} <b>{UtcToLocal(CreatedOn).Value.ToString(DateTimeFormat)}</ b >";
|
||||
}
|
||||
|
||||
_text += "</p>";
|
||||
@ -69,7 +69,7 @@
|
||||
|
||||
if (ModifiedOn != null)
|
||||
{
|
||||
_text += $" {Localizer["On"]} <b>{UtcToLocal(ModifiedOn).Value.ToString(DateTimeFormat)}</b>";
|
||||
_text += $" {Localizer["On"]} <b>{UtcToLocal(ModifiedOn).Value.ToString(DateTimeFormat)}</ b >";
|
||||
}
|
||||
|
||||
_text += "</p>";
|
||||
@ -86,7 +86,7 @@
|
||||
|
||||
if (DeletedOn != null)
|
||||
{
|
||||
_text += $" {Localizer["On"]} <b>{UtcToLocal(DeletedOn).Value.ToString(DateTimeFormat)}</b>";
|
||||
_text += $" {Localizer["On"]} <b>{UtcToLocal(DeletedOn).Value.ToString(DateTimeFormat)}</ b >";
|
||||
}
|
||||
|
||||
_text += "</p>";
|
||||
|
@ -107,7 +107,7 @@
|
||||
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private List<Folder> _folders = new List<Folder>();
|
||||
private List<Folder> _folders;
|
||||
private List<File> _files = new List<File>();
|
||||
private string _fileinputid = string.Empty;
|
||||
private string _progressinfoid = string.Empty;
|
||||
@ -157,9 +157,6 @@
|
||||
[Parameter]
|
||||
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
||||
|
||||
[Parameter]
|
||||
public bool AnonymizeUploadFilenames { get; set; } = false; // optional - indicate if file names should be anonymized on upload - default false
|
||||
|
||||
[Parameter]
|
||||
public int ChunkSize { get; set; } = 1; // optional - size of file chunks to upload in MB
|
||||
|
||||
@ -198,22 +195,19 @@
|
||||
Filter = "nupkg";
|
||||
ShowSuccess = true;
|
||||
}
|
||||
else
|
||||
|
||||
if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder)
|
||||
{
|
||||
// folder path specified rather than folderid
|
||||
if (!string.IsNullOrEmpty(Folder))
|
||||
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
||||
if (folder != null)
|
||||
{
|
||||
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
||||
if (folder != null)
|
||||
{
|
||||
FolderId = folder.FolderId;
|
||||
}
|
||||
else
|
||||
{
|
||||
FolderId = -1;
|
||||
_message = "Folder Path " + Folder + " Does Not Exist";
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
FolderId = folder.FolderId;
|
||||
}
|
||||
else
|
||||
{
|
||||
FolderId = -1;
|
||||
_message = "Folder Path " + Folder + " Does Not Exist";
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,24 +242,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
await SetImage();
|
||||
|
||||
if (!string.IsNullOrEmpty(Filter))
|
||||
{
|
||||
_filter = "." + Filter.Replace(",", ",.");
|
||||
}
|
||||
|
||||
GetFolderPermission();
|
||||
await SetImage();
|
||||
await GetFiles();
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
private void GetFolderPermission()
|
||||
private async Task GetFiles()
|
||||
{
|
||||
_haseditpermission = false;
|
||||
if (Folder == Constants.PackagesFolder)
|
||||
{
|
||||
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);
|
||||
_files = new List<File>();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -273,44 +268,6 @@
|
||||
if (folder != null)
|
||||
{
|
||||
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.PermissionList);
|
||||
}
|
||||
else
|
||||
{
|
||||
_haseditpermission = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetImage()
|
||||
{
|
||||
_image = string.Empty;
|
||||
_file = null;
|
||||
if (FileId != -1)
|
||||
{
|
||||
_file = await FileService.GetFileAsync(FileId);
|
||||
if (_file != null && ShowImage && _file.ImageHeight != 0 && _file.ImageWidth != 0)
|
||||
{
|
||||
var maxwidth = 200;
|
||||
var maxheight = 200;
|
||||
|
||||
var ratioX = (double)maxwidth / (double)_file.ImageWidth;
|
||||
var ratioY = (double)maxheight / (double)_file.ImageHeight;
|
||||
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
||||
|
||||
_image = "<img src=\"" + _file.Url + "\" alt=\"" + _file.Name +
|
||||
"\" width=\"" + Convert.ToInt32(_file.ImageWidth * ratio).ToString() +
|
||||
"\" height=\"" + Convert.ToInt32(_file.ImageHeight * ratio).ToString() + "\" />";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetFiles()
|
||||
{
|
||||
if (ShowFiles)
|
||||
{
|
||||
Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId);
|
||||
if (folder != null)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Browse, folder.PermissionList))
|
||||
{
|
||||
_files = await FileService.GetFilesAsync(FolderId);
|
||||
@ -322,6 +279,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
_haseditpermission = false;
|
||||
_files = new List<File>();
|
||||
}
|
||||
if (_filter != "*")
|
||||
@ -345,11 +303,12 @@
|
||||
try
|
||||
{
|
||||
FolderId = int.Parse((string)e.Value);
|
||||
await OnSelectFolder.InvokeAsync(FolderId);
|
||||
FileId = -1;
|
||||
GetFolderPermission();
|
||||
await SetImage();
|
||||
await GetFiles();
|
||||
FileId = -1;
|
||||
_file = null;
|
||||
_image = string.Empty;
|
||||
|
||||
await OnSelectFolder.InvokeAsync(FolderId);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -364,14 +323,37 @@
|
||||
{
|
||||
_message = string.Empty;
|
||||
FileId = int.Parse((string)e.Value);
|
||||
await SetImage();
|
||||
#pragma warning disable CS0618
|
||||
await OnSelect.InvokeAsync(FileId);
|
||||
#pragma warning restore CS0618
|
||||
await OnSelectFile.InvokeAsync(FileId);
|
||||
await SetImage();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task SetImage()
|
||||
{
|
||||
_image = string.Empty;
|
||||
_file = null;
|
||||
if (FileId != -1)
|
||||
{
|
||||
_file = await FileService.GetFileAsync(FileId);
|
||||
if (_file != null && ShowImage && _file.ImageHeight != 0 && _file.ImageWidth != 0)
|
||||
{
|
||||
var maxwidth = 200;
|
||||
var maxheight = 200;
|
||||
|
||||
var ratioX = (double)maxwidth / (double)_file.ImageWidth;
|
||||
var ratioY = (double)maxheight / (double)_file.ImageHeight;
|
||||
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
||||
|
||||
_image = "<img src=\"" + _file.Url + "\" alt=\"" + _file.Name +
|
||||
"\" width=\"" + Convert.ToInt32(_file.ImageWidth * ratio).ToString() +
|
||||
"\" height=\"" + Convert.ToInt32(_file.ImageHeight * ratio).ToString() + "\" />";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UploadFiles()
|
||||
{
|
||||
_message = string.Empty;
|
||||
@ -426,7 +408,7 @@
|
||||
}
|
||||
|
||||
// upload files
|
||||
var success = await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken, jwt, chunksize, AnonymizeUploadFilenames, tokenSource.Token);
|
||||
var success = await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken, jwt, chunksize, tokenSource.Token);
|
||||
|
||||
// reset progress indicators
|
||||
if (ShowProgress)
|
||||
@ -448,27 +430,6 @@
|
||||
_message = Localizer["Success.File.Upload"];
|
||||
_messagetype = MessageType.Success;
|
||||
}
|
||||
|
||||
FileId = -1;
|
||||
if (Folder != Constants.PackagesFolder && !AnonymizeUploadFilenames)
|
||||
{
|
||||
// set FileId to first file in upload collection
|
||||
var file = await FileService.GetFileAsync(int.Parse(folder), uploads[0].Split(":")[0]);
|
||||
if (file != null)
|
||||
{
|
||||
FileId = file.FileId;
|
||||
}
|
||||
}
|
||||
|
||||
await OnUpload.InvokeAsync(FileId);
|
||||
#pragma warning disable CS0618
|
||||
await OnSelect.InvokeAsync(FileId);
|
||||
#pragma warning restore CS0618
|
||||
await OnSelectFile.InvokeAsync(FileId);
|
||||
|
||||
await SetImage();
|
||||
await GetFiles();
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -476,6 +437,28 @@
|
||||
_message = Localizer["Error.File.Upload"];
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
|
||||
if (Folder == Constants.PackagesFolder)
|
||||
{
|
||||
await OnUpload.InvokeAsync(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set FileId to first file in upload collection
|
||||
var file = await FileService.GetFileAsync(int.Parse(folder), uploads[0].Split(":")[0]);
|
||||
if (file != null)
|
||||
{
|
||||
FileId = file.FileId;
|
||||
await SetImage();
|
||||
#pragma warning disable CS0618
|
||||
await OnSelect.InvokeAsync(FileId);
|
||||
#pragma warning restore CS0618
|
||||
await OnSelectFile.InvokeAsync(FileId);
|
||||
await OnUpload.InvokeAsync(FileId);
|
||||
}
|
||||
await GetFiles();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -488,6 +471,7 @@
|
||||
finally {
|
||||
tokenSource.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -517,49 +501,47 @@
|
||||
_messagetype = MessageType.Success;
|
||||
}
|
||||
|
||||
FileId = -1;
|
||||
await GetFiles();
|
||||
FileId = -1;
|
||||
await SetImage();
|
||||
#pragma warning disable CS0618
|
||||
await OnSelect.InvokeAsync(FileId);
|
||||
#pragma warning restore CS0618
|
||||
await OnSelectFile.InvokeAsync(FileId);
|
||||
|
||||
await SetImage();
|
||||
await GetFiles();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message);
|
||||
|
||||
_message = Localizer["Error.File.Delete"];
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
}
|
||||
_message = Localizer["Error.File.Delete"];
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetFileId() => FileId;
|
||||
public int GetFileId() => FileId;
|
||||
|
||||
public int GetFolderId() => FolderId;
|
||||
public int GetFolderId() => FolderId;
|
||||
|
||||
public File GetFile() => _file;
|
||||
public File GetFile() => _file;
|
||||
|
||||
public async Task Refresh()
|
||||
{
|
||||
await Refresh(-1);
|
||||
}
|
||||
public async Task Refresh()
|
||||
{
|
||||
await Refresh(-1);
|
||||
}
|
||||
|
||||
public async Task Refresh(int fileId)
|
||||
{
|
||||
await GetFiles();
|
||||
FileId = -1;
|
||||
if (fileId != -1)
|
||||
public async Task Refresh(int fileId)
|
||||
{
|
||||
await GetFiles();
|
||||
if (fileId != -1)
|
||||
{
|
||||
var file = _files.Where(item => item.FileId == fileId).FirstOrDefault();
|
||||
if (file != null)
|
||||
{
|
||||
FileId = file.FileId;
|
||||
await SetImage();
|
||||
}
|
||||
}
|
||||
await SetImage();
|
||||
StateHasChanged();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
@namespace Oqtane.Modules.Controls
|
||||
@using System.IO
|
||||
@using Radzen
|
||||
@using Radzen.Blazor
|
||||
@inject DialogService DialogService
|
||||
@inject IStringLocalizer<Oqtane.Modules.Controls.RadzenTextEditor> Localizer
|
||||
|
||||
<div class="d-flex">
|
||||
<FileManager @ref="_fileManager" Filter="@Filters" />
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
|
||||
</div>
|
||||
<div class="mt-1 text-end">
|
||||
<RadzenButton Text="OK" Click=@OnOkClick />
|
||||
<RadzenButton Text="Cancel" Click=@OnCancelClick ButtonStyle="ButtonStyle.Secondary" />
|
||||
</div>
|
||||
@code {
|
||||
private FileManager _fileManager;
|
||||
private string _message = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Filters { get; set; }
|
||||
|
||||
private void OnCancelClick()
|
||||
{
|
||||
DialogService.Close(null);
|
||||
}
|
||||
|
||||
private void OnOkClick()
|
||||
{
|
||||
_message = string.Empty;
|
||||
var file = _fileManager.GetFile();
|
||||
if (file != null)
|
||||
{
|
||||
var result = $"<img src=\"{file.Url}\" style=\"max-width: 100%\" alt=\"{file.Name}\" />";
|
||||
DialogService.Close(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = Localizer["Message.Require.Image"];
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
@ -9,26 +9,62 @@
|
||||
|
||||
@if (_permissions != null)
|
||||
{
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<table class="table table-borderless">
|
||||
<tbody>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<table class="table table-borderless">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="col">@Localizer["Role"]</th>
|
||||
@foreach (var permissionname in _permissionnames)
|
||||
{
|
||||
<th style="text-align: center; width: 1px;">@((MarkupString)DisplayPermissionName(permissionname).Replace(" ", "<br />"))</th>
|
||||
}
|
||||
</tr>
|
||||
@foreach (Role role in _roles)
|
||||
{
|
||||
<tr>
|
||||
<th scope="col">@Localizer["Role"]</th>
|
||||
<td>@role.Name</td>
|
||||
@foreach (var permissionname in _permissionnames)
|
||||
{
|
||||
<th style="text-align: center; width: 1px;">@((MarkupString)DisplayPermissionName(permissionname).Replace(" ", "<br />"))</th>
|
||||
<td style="text-align: center;">
|
||||
<TriStateCheckBox Value=@GetPermissionValue(permissionname, role.Name, -1) Disabled="@GetPermissionDisabled(permissionname, role.Name)" OnChange="@(e => PermissionChanged(e, permissionname, role.Name, -1))" />
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
@foreach (Role role in _roles)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@if (_users.Count != 0)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-borderless">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">@Localizer["User"]</th>
|
||||
@foreach (var permissionname in _permissionnames)
|
||||
{
|
||||
<th style="text-align: center; width: 1px;">@((MarkupString)DisplayPermissionName(permissionname).Replace(" ", "<br />"))</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (User user in _users)
|
||||
{
|
||||
<tr>
|
||||
<td>@role.Name</td>
|
||||
<td>@user.DisplayName (@user.Username)</td>
|
||||
@foreach (var permissionname in _permissionnames)
|
||||
{
|
||||
<td style="text-align: center;">
|
||||
<TriStateCheckBox Value="@GetPermissionValue(permissionname, role.Name, -1)" Disabled="@GetPermissionDisabled(permissionname, role.Name)" OnChange="@(e => PermissionChanged(e, permissionname, role.Name, -1))" />
|
||||
<td style="text-align: center; width: 1px;">
|
||||
<TriStateCheckBox Value=@GetPermissionValue(permissionname, "", user.UserId) Disabled="@GetPermissionDisabled(permissionname, "")" OnChange="@(e => PermissionChanged(e, permissionname, "", user.UserId))" />
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
@ -36,242 +72,200 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@if (_users.Count != 0)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-borderless">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">@Localizer["User"]</th>
|
||||
@foreach (var permissionname in _permissionnames)
|
||||
{
|
||||
<th style="text-align: center; width: 1px;">@((MarkupString)DisplayPermissionName(permissionname).Replace(" ", "<br />"))</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (User user in _users)
|
||||
{
|
||||
<tr>
|
||||
<td>@user.DisplayName (@user.Username)</td>
|
||||
@foreach (var permissionname in _permissionnames)
|
||||
{
|
||||
<td style="text-align: center; width: 1px;">
|
||||
<TriStateCheckBox Value="@GetPermissionValue(permissionname, "", user.UserId)" Disabled="@GetPermissionDisabled(permissionname, "")" OnChange="@(e => PermissionChanged(e, permissionname, "", user.UserId))" />
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<br />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-11">
|
||||
<AutoComplete OnSearch="GetUsers" Placeholder="@Localizer["Username.Enter"]" @ref="_user" />
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<button type="button" class="btn btn-primary" @onclick="AddUser">@SharedLocalizer["Add"]</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<ModuleMessage Type="MessageType.Warning" Message="@_message" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-11">
|
||||
<AutoComplete OnSearch="GetUsers" Placeholder="@Localizer["Username.Enter"]" @ref="_user" />
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<button type="button" class="btn btn-primary" @onclick="AddUser">@SharedLocalizer["Add"]</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<ModuleMessage Type="MessageType.Warning" Message="@_message" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<string> _permissionnames;
|
||||
private List<Permission> _permissions;
|
||||
private List<Role> _roles;
|
||||
private List<User> _users = new List<User>();
|
||||
private AutoComplete _user;
|
||||
private string _message = string.Empty;
|
||||
private List<string> _permissionnames;
|
||||
private List<Permission> _permissions;
|
||||
private List<Role> _roles;
|
||||
private List<User> _users = new List<User>();
|
||||
private AutoComplete _user;
|
||||
private string _message = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string EntityName { get; set; }
|
||||
[Parameter]
|
||||
public string EntityName { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string PermissionNames { get; set; }
|
||||
[Parameter]
|
||||
public string PermissionNames { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Permissions { get; set; } // deprecated - use PermissionList instead
|
||||
[Parameter]
|
||||
public string Permissions { get; set; } // deprecated - use PermissionList instead
|
||||
|
||||
[Parameter]
|
||||
public List<Permission> PermissionList { get; set; }
|
||||
[Parameter]
|
||||
public List<Permission> PermissionList { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Permissions))
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
|
||||
}
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Permissions))
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
|
||||
}
|
||||
|
||||
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId, true);
|
||||
_roles.RemoveAll(item => item.Name == RoleNames.Host); // remove host role
|
||||
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId, true);
|
||||
if (!UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_roles.RemoveAll(item => item.Name == RoleNames.Host);
|
||||
}
|
||||
|
||||
// get permission names
|
||||
if (string.IsNullOrEmpty(PermissionNames))
|
||||
{
|
||||
_permissionnames = new List<string>();
|
||||
_permissionnames.Add(Shared.PermissionNames.View);
|
||||
_permissionnames.Add(Shared.PermissionNames.Edit);
|
||||
}
|
||||
else
|
||||
{
|
||||
_permissionnames = PermissionNames.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
}
|
||||
// get permission names
|
||||
if (string.IsNullOrEmpty(PermissionNames))
|
||||
{
|
||||
_permissionnames = new List<string>();
|
||||
_permissionnames.Add(Shared.PermissionNames.View);
|
||||
_permissionnames.Add(Shared.PermissionNames.Edit);
|
||||
}
|
||||
else
|
||||
{
|
||||
_permissionnames = PermissionNames.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
}
|
||||
|
||||
// initialize permissions
|
||||
_permissions = new List<Permission>();
|
||||
if (PermissionList != null && PermissionList.Any())
|
||||
{
|
||||
foreach (var permission in PermissionList)
|
||||
{
|
||||
_permissions.Add(permission);
|
||||
if (permission.UserId != null)
|
||||
{
|
||||
if (!_users.Any(item => item.UserId == permission.UserId.Value))
|
||||
{
|
||||
_users.Add(await UserService.GetUserAsync(permission.UserId.Value, ModuleState.SiteId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string permissionname in _permissionnames)
|
||||
{
|
||||
// permission names can be in the form of "EntityName:PermissionName:Roles"
|
||||
if (permissionname.Contains(":"))
|
||||
{
|
||||
var segments = permissionname.Split(':');
|
||||
if (segments.Length == 3)
|
||||
{
|
||||
foreach (var role in segments[2].Split(';'))
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, segments[0], segments[1], role, null, true));
|
||||
}
|
||||
// ensure admin access
|
||||
if (!_permissions.Any(item => item.EntityName == segments[0] && item.PermissionName == segments[1] && item.RoleName == RoleNames.Admin))
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, segments[0], segments[1], RoleNames.Admin, null, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, EntityName, permissionname, RoleNames.Admin, null, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// initialize permissions
|
||||
_permissions = new List<Permission>();
|
||||
if (PermissionList != null && PermissionList.Any())
|
||||
{
|
||||
foreach (var permission in PermissionList)
|
||||
{
|
||||
_permissions.Add(permission);
|
||||
if (permission.UserId != null)
|
||||
{
|
||||
if (!_users.Any(item => item.UserId == permission.UserId.Value))
|
||||
{
|
||||
_users.Add(await UserService.GetUserAsync(permission.UserId.Value, ModuleState.SiteId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string permissionname in _permissionnames)
|
||||
{
|
||||
// permission names can be in the form of "EntityName:PermissionName:Roles"
|
||||
if (permissionname.Contains(":"))
|
||||
{
|
||||
var segments = permissionname.Split(':');
|
||||
if (segments.Length == 3)
|
||||
{
|
||||
foreach (var role in segments[2].Split(';'))
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, segments[0], segments[1], role, null, true));
|
||||
}
|
||||
// ensure admin access
|
||||
if (!_permissions.Any(item => item.EntityName == segments[0] && item.PermissionName == segments[1] && item.RoleName == RoleNames.Admin))
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, segments[0], segments[1], RoleNames.Admin, null, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, EntityName, permissionname, RoleNames.Admin, null, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetPermissionName(string permissionName)
|
||||
{
|
||||
return (permissionName.Contains(":")) ? permissionName.Split(':')[1] : permissionName;
|
||||
}
|
||||
private string GetPermissionName(string permissionName)
|
||||
{
|
||||
return (permissionName.Contains(":")) ? permissionName.Split(':')[1] : permissionName;
|
||||
}
|
||||
|
||||
private string GetEntityName(string permissionName)
|
||||
{
|
||||
return (permissionName.Contains(":")) ? permissionName.Split(':')[0] : EntityName;
|
||||
}
|
||||
private string GetEntityName(string permissionName)
|
||||
{
|
||||
return (permissionName.Contains(":")) ? permissionName.Split(':')[0] : EntityName;
|
||||
}
|
||||
|
||||
private string DisplayPermissionName(string permissionName)
|
||||
{
|
||||
var name = Localizer[GetPermissionName(permissionName)].ToString();
|
||||
name += " " + Localizer[GetEntityName(permissionName)].ToString();
|
||||
return name;
|
||||
}
|
||||
private string DisplayPermissionName(string permissionName)
|
||||
{
|
||||
var name = Localizer[GetPermissionName(permissionName)].ToString();
|
||||
name += " " + Localizer[GetEntityName(permissionName)].ToString();
|
||||
return name;
|
||||
}
|
||||
|
||||
private bool? GetPermissionValue(string permissionName, string roleName, int userId)
|
||||
{
|
||||
bool? isauthorized = null;
|
||||
if (roleName != "")
|
||||
{
|
||||
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.RoleName == roleName);
|
||||
if (permission != null)
|
||||
{
|
||||
isauthorized = permission.IsAuthorized;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.UserId == userId);
|
||||
if (permission != null)
|
||||
{
|
||||
isauthorized = permission.IsAuthorized;
|
||||
}
|
||||
}
|
||||
return isauthorized;
|
||||
}
|
||||
private bool? GetPermissionValue(string permissionName, string roleName, int userId)
|
||||
{
|
||||
bool? isauthorized = null;
|
||||
if (roleName != "")
|
||||
{
|
||||
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.RoleName == roleName);
|
||||
if (permission != null)
|
||||
{
|
||||
isauthorized = permission.IsAuthorized;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.UserId == userId);
|
||||
if (permission != null)
|
||||
{
|
||||
isauthorized = permission.IsAuthorized;
|
||||
}
|
||||
}
|
||||
return isauthorized;
|
||||
}
|
||||
|
||||
private bool GetPermissionDisabled(string permissionName, string roleName)
|
||||
{
|
||||
var disabled = false;
|
||||
private bool GetPermissionDisabled(string permissionName, string roleName)
|
||||
{
|
||||
if (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetEntityName(permissionName) != EntityName && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// administrator role permissions can only be changed by a host
|
||||
if (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
// API permissions can only be changed by an administrator
|
||||
if (GetEntityName(permissionName) != EntityName && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
return disabled;
|
||||
}
|
||||
|
||||
private bool? PermissionChanged(bool? value, string permissionName, string roleName, int userId)
|
||||
{
|
||||
if (roleName != "")
|
||||
{
|
||||
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.RoleName == roleName);
|
||||
if (permission != null)
|
||||
{
|
||||
_permissions.Remove(permission);
|
||||
}
|
||||
|
||||
// system roles cannot be denied - only custom roles can be denied
|
||||
var role = _roles.FirstOrDefault(item => item.Name == roleName);
|
||||
if (value != null && !value.Value && role.IsSystem)
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), roleName, null, value.Value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.UserId == userId);
|
||||
if (permission != null)
|
||||
{
|
||||
_permissions.Remove(permission);
|
||||
}
|
||||
if (value != null)
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), null, userId, value.Value));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
private void PermissionChanged(bool? value, string permissionName, string roleName, int userId)
|
||||
{
|
||||
if (roleName != "")
|
||||
{
|
||||
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.RoleName == roleName);
|
||||
if (permission != null)
|
||||
{
|
||||
_permissions.Remove(permission);
|
||||
}
|
||||
if (value != null)
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), roleName, null, value.Value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.UserId == userId);
|
||||
if (permission != null)
|
||||
{
|
||||
_permissions.Remove(permission);
|
||||
}
|
||||
if (value != null)
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), null, userId, value.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, string>> GetUsers(string filter)
|
||||
{
|
||||
@ -311,20 +305,29 @@
|
||||
|
||||
private void ValidatePermissions()
|
||||
{
|
||||
// remove deny all users, unauthenticated, and registered users
|
||||
var permissions = _permissions.Where(item => !item.IsAuthorized &&
|
||||
(item.RoleName == RoleNames.Everyone || item.RoleName == RoleNames.Unauthenticated || item.RoleName == RoleNames.Registered)).ToList();
|
||||
foreach (var permission in permissions)
|
||||
{
|
||||
_permissions.Remove(permission);
|
||||
}
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
// remove host role permissions
|
||||
var permissions = _permissions.Where(item => item.RoleName == RoleNames.Host).ToList();
|
||||
foreach (var permission in permissions)
|
||||
{
|
||||
_permissions.Remove(permission);
|
||||
}
|
||||
// add host role permissions if administrator role is not assigned (to prevent lockout)
|
||||
foreach (var permissionname in _permissionnames)
|
||||
// remove deny administrators and host users
|
||||
permissions = _permissions.Where(item => !item.IsAuthorized &&
|
||||
(item.RoleName == RoleNames.Admin || item.RoleName == RoleNames.Host)).ToList();
|
||||
foreach (var permission in permissions)
|
||||
{
|
||||
if (!_permissions.Any(item => item.EntityName == GetEntityName(permissionname) && item.PermissionName == GetPermissionName(permissionname) && item.RoleName == RoleNames.Admin))
|
||||
_permissions.Remove(permission);
|
||||
}
|
||||
foreach (var permissionname in _permissionnames)
|
||||
{
|
||||
// add administrators role if neither host or administrator is assigned
|
||||
if (!_permissions.Any(item => item.EntityName == GetEntityName(permissionname) && item.PermissionName == GetPermissionName(permissionname) &&
|
||||
(item.RoleName == RoleNames.Admin || item.RoleName == RoleNames.Host)))
|
||||
{
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionname), GetPermissionName(permissionname), RoleNames.Host, null, true));
|
||||
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionname), GetPermissionName(permissionname), RoleNames.Admin, null, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Modules.Controls
|
||||
{
|
||||
public class QuillJSTextEditorInterop
|
||||
public class QuillEditorInterop
|
||||
{
|
||||
private readonly IJSRuntime _jsRuntime;
|
||||
|
||||
public QuillJSTextEditorInterop(IJSRuntime jsRuntime)
|
||||
public QuillEditorInterop(IJSRuntime jsRuntime)
|
||||
{
|
||||
_jsRuntime = jsRuntime;
|
||||
}
|
@ -177,14 +177,14 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
public string Name => "QuillJS Text Editor";
|
||||
public string Name => "QuillJS";
|
||||
|
||||
private string resourceType = "Oqtane.Modules.Controls.QuillJSTextEditor, Oqtane.Client";
|
||||
|
||||
private bool _settingsLoaded;
|
||||
private bool _initialized = false;
|
||||
|
||||
private QuillJSTextEditorInterop _interop;
|
||||
private QuillEditorInterop _interop;
|
||||
private FileManager _fileManager;
|
||||
private string _activetab = "Rich";
|
||||
private bool _allowSettings = false;
|
||||
@ -246,14 +246,14 @@
|
||||
|
||||
public override List<Resource> Resources { get; set; } = new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/texteditors/quilljs/quill.min.js", Location = ResourceLocation.Body },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/texteditors/quilljs/quill-blot-formatter.min.js", Location = ResourceLocation.Body },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/texteditors/quilljs/quill-interop.js", Location = ResourceLocation.Body }
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js", Location = ResourceLocation.Body },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js", Location = ResourceLocation.Body },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body }
|
||||
};
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_interop = new QuillJSTextEditorInterop(JSRuntime);
|
||||
_interop = new QuillEditorInterop(JSRuntime);
|
||||
|
||||
if (string.IsNullOrEmpty(Placeholder))
|
||||
{
|
||||
@ -277,7 +277,7 @@
|
||||
{
|
||||
// include CSS theme
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.IncludeLink("", "stylesheet", $"{PageState?.Alias.BaseUrl}/css/texteditors/quilljs/quill.{_theme}.css", "text/css", "", "", "");
|
||||
await interop.IncludeLink("", "stylesheet", $"{PageState?.Alias.BaseUrl}/css/quill/quill.{_theme}.css", "text/css", "", "", "");
|
||||
}
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
@ -1,222 +0,0 @@
|
||||
@namespace Oqtane.Modules.Controls
|
||||
@using System.IO
|
||||
@using Radzen
|
||||
@using Radzen.Blazor
|
||||
@inherits ModuleControlBase
|
||||
@inject DialogService DialogService
|
||||
@inject Radzen.ThemeService ThemeService
|
||||
@inject ISettingService SettingService
|
||||
@inject IRadzenEditorSettingService EditorSettingService
|
||||
@inject IStringLocalizer<Oqtane.Modules.Controls.RadzenTextEditor> Localizer
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-3">
|
||||
@Localizer["Scope"]
|
||||
</div>
|
||||
<div class="col-12 col-sm-9">
|
||||
<RadzenRadioButtonList @bind-Value="@_settingScope" TValue="int" Change="OnScopeChanged">
|
||||
<Items>
|
||||
<RadzenRadioButtonListItem Text="@Localizer["Site"]" Value="0" />
|
||||
<RadzenRadioButtonListItem Text="@Localizer["Module"]" Value="1" />
|
||||
</Items>
|
||||
</RadzenRadioButtonList>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-12 col-sm-3">
|
||||
@Localizer["Theme"]
|
||||
</div>
|
||||
<div class="col-12 col-sm-9">
|
||||
<RadzenDropDown @bind-Value="_theme" TValue="string" Data="@_themes" Style="width: 100%;">
|
||||
<Template>
|
||||
<span>@Localizer[$"theme.{context}"]</span>
|
||||
</Template>
|
||||
</RadzenDropDown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-12 col-sm-3">
|
||||
@Localizer["Background"]
|
||||
</div>
|
||||
<div class="col-12 col-sm-9">
|
||||
<RadzenDropDown @bind-Value="_background" TValue="string" Data="_backgroundColors" Style="width: 100%;">
|
||||
<Template>
|
||||
<span>@Localizer[context]</span>
|
||||
</Template>
|
||||
</RadzenDropDown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-12 col-sm-3">
|
||||
@Localizer["Toolbar"]
|
||||
</div>
|
||||
<div class="col-12 col-sm-9">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-7">
|
||||
<RadzenDropDown TValue="string" @bind-Value="_addToolbarItem" Data="@RadzenEditorDefinitions.ToolbarItems.Keys" Style="width: 100%;">
|
||||
</RadzenDropDown>
|
||||
</div>
|
||||
<div class="col-12 col-sm-5 text-end">
|
||||
<button type="button" class="btn btn-primary" @onclick="AddToolbarItem">@Localizer["Add"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="ResetToolbarItem">@Localizer["Reset"]</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2" style="max-height: 500px; overflow-y: scroll;">
|
||||
<div class="col">
|
||||
<RadzenDropZoneContainer TItem="ToolbarItem" Data="_toolbarItems"
|
||||
ItemSelector="@((i, z) => true)"
|
||||
CanDrop="@((i) => true)"
|
||||
Drop="OnToolbarItemDrop"
|
||||
ItemRender="OnToolbarItemRender">
|
||||
<ChildContent>
|
||||
<RadzenDropZone TItem="ToolbarItem" class="rounded">
|
||||
</RadzenDropZone>
|
||||
</ChildContent>
|
||||
<Template>
|
||||
<div>
|
||||
<strong>@context.Name</strong>
|
||||
<RadzenButton Icon="delete" Click="@((e) => DeleteToolbarItem(context))" Size="ButtonSize.ExtraSmall" ButtonStyle="ButtonStyle.Light" />
|
||||
</div>
|
||||
</Template>
|
||||
</RadzenDropZoneContainer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-end">
|
||||
<RadzenButton Text="OK" Click=@OnOkClick />
|
||||
<RadzenButton Text="Cancel" Click=@OnCancelClick ButtonStyle="ButtonStyle.Secondary" />
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private readonly IList<string> _themes = new List<string>
|
||||
{
|
||||
"default",
|
||||
"dark",
|
||||
"material",
|
||||
"material-dark",
|
||||
"standard",
|
||||
"standard-dark",
|
||||
"humanistic",
|
||||
"humanistic-dark",
|
||||
"software",
|
||||
"software-dark"
|
||||
};
|
||||
private readonly IList<string> _backgroundColors = new List<string> { "Default", "Light", "Dark" };
|
||||
|
||||
private int _settingScope;
|
||||
private string _theme;
|
||||
private string _background;
|
||||
private IList<ToolbarItem> _toolbarItems = new List<ToolbarItem>();
|
||||
private string _addToolbarItem;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_settingScope = await EditorSettingService.GetSettingScopeAsync(ModuleState.ModuleId);
|
||||
|
||||
await LoadSettings();
|
||||
}
|
||||
|
||||
private async Task<RadzenEditorSetting> LoadSettingsFromModule()
|
||||
{
|
||||
return await EditorSettingService.LoadSettingsFromModuleAsync(ModuleState.ModuleId);
|
||||
}
|
||||
|
||||
private async Task<RadzenEditorSetting> LoadSettingsFromSite()
|
||||
{
|
||||
return await EditorSettingService.LoadSettingsFromSiteAsync(PageState.Site.SiteId);
|
||||
}
|
||||
|
||||
private async Task LoadSettings()
|
||||
{
|
||||
var editorSetting = _settingScope == 1 ? await LoadSettingsFromModule() : await LoadSettingsFromSite();
|
||||
_theme = editorSetting.Theme;
|
||||
_background = editorSetting.Background;
|
||||
_toolbarItems = editorSetting.ToolbarItems.Split(',').Select((v, i) =>
|
||||
{
|
||||
return new ToolbarItem { Key = i, Name = v };
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
private async Task OnScopeChanged()
|
||||
{
|
||||
await LoadSettings();
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void AddToolbarItem()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_addToolbarItem))
|
||||
{
|
||||
_toolbarItems.Add(new ToolbarItem { Key = _toolbarItems.Count, Name = _addToolbarItem });
|
||||
_addToolbarItem = string.Empty;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetToolbarItem()
|
||||
{
|
||||
_toolbarItems = RadzenEditorDefinitions.DefaultToolbarItems.Split(',').Select((v, i) =>
|
||||
{
|
||||
return new ToolbarItem { Key = i, Name = v };
|
||||
}).ToList();
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void DeleteToolbarItem(ToolbarItem item)
|
||||
{
|
||||
_toolbarItems.Remove(item);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void OnCancelClick()
|
||||
{
|
||||
DialogService.Close(false);
|
||||
}
|
||||
|
||||
private async Task OnOkClick()
|
||||
{
|
||||
var editorSetting = new RadzenEditorSetting
|
||||
{
|
||||
Theme = _theme,
|
||||
Background = _background,
|
||||
ToolbarItems = string.Join(",", _toolbarItems.Select(i => i.Name))
|
||||
};
|
||||
await EditorSettingService.UpdateSettingScopeAsync(ModuleState.ModuleId, _settingScope);
|
||||
if (_settingScope == 1)
|
||||
{
|
||||
await EditorSettingService.SaveModuleSettingsAsync(ModuleState.ModuleId, editorSetting);
|
||||
}
|
||||
else
|
||||
{
|
||||
await EditorSettingService.SaveSiteSettingsAsync(PageState.Site.SiteId, editorSetting);
|
||||
}
|
||||
|
||||
DialogService.Close(true);
|
||||
}
|
||||
|
||||
private void OnToolbarItemDrop(RadzenDropZoneItemEventArgs<ToolbarItem> args)
|
||||
{
|
||||
if (args.ToItem != null && args.ToItem.Key != args.Item.Key)
|
||||
{
|
||||
_toolbarItems.Remove(args.Item);
|
||||
_toolbarItems.Insert(_toolbarItems.IndexOf(args.ToItem), args.Item);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnToolbarItemRender(RadzenDropZoneItemRenderEventArgs<ToolbarItem> args)
|
||||
{
|
||||
args.Attributes.Add("class", "rz-card rz-variant-flat rz-background-color-primary-lighter rz-color-on-primary-lighter rz-p-2 d-inline-block ms-1 mt-1");
|
||||
}
|
||||
|
||||
public class ToolbarItem
|
||||
{
|
||||
public int Key { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
public string Name => "Basic Text Editor";
|
||||
public string Name => "TextArea";
|
||||
|
||||
private ElementReference _editor;
|
||||
private string _content;
|
@ -1,194 +0,0 @@
|
||||
@using Microsoft.Extensions.Configuration
|
||||
@using Oqtane.Interfaces
|
||||
@using System.Text.RegularExpressions
|
||||
@using Radzen
|
||||
@using Radzen.Blazor
|
||||
|
||||
@namespace Oqtane.Modules.Controls
|
||||
@inherits ModuleControlBase
|
||||
@implements ITextEditor
|
||||
@implements IDisposable
|
||||
@inject Radzen.ThemeService ThemeService
|
||||
@inject IRadzenEditorSettingService EditorSettingService
|
||||
@inject DialogService DialogService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IStringLocalizer<Oqtane.Modules.Controls.RadzenTextEditor> Localizer
|
||||
|
||||
<RadzenTheme Theme="@RadzenEditorDefinitions.DefaultTheme" />
|
||||
<RadzenComponents />
|
||||
<RadzenHtmlEditor @ref="_editor" Visible="_visible" Placeholder="@Placeholder" style="@($"height: {Height}px;")"
|
||||
@bind-Value="_value" Execute="OnExecute" class="rz-text-editor">
|
||||
<ChildContent>
|
||||
@_toolbar
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
<RadzenHtmlEditorCustomTool CommandName="Settings" Icon="settings" Title="@Localizer["Settings"]" />
|
||||
}
|
||||
</ChildContent>
|
||||
|
||||
</RadzenHtmlEditor>
|
||||
|
||||
@code {
|
||||
private Oqtane.Modules.Controls.RadzenTextEditorInterop _interop;
|
||||
private RadzenHtmlEditor _editor;
|
||||
private string _value;
|
||||
private bool _visible = false;
|
||||
private string _theme;
|
||||
private string _background;
|
||||
private IList<string> _toolbarItems;
|
||||
private RenderFragment _toolbar;
|
||||
|
||||
[Parameter]
|
||||
public string Placeholder { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int Height { get; set; } = 450;
|
||||
|
||||
public string Name => "Radzen HTML Editor";
|
||||
|
||||
public override List<Resource> Resources { get; set; } = new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Script, Url = "_content/Radzen.Blazor/Radzen.Blazor.js", Location = ResourceLocation.Body },
|
||||
new Resource { ResourceType = ResourceType.Script, Url = "js/texteditors/radzen/radzen-interop.js", Location = ResourceLocation.Body }
|
||||
};
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_interop = new Oqtane.Modules.Controls.RadzenTextEditorInterop(JSRuntime);
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.IncludeLink("", "stylesheet", $"{PageState?.Alias.BaseUrl}/css/texteditors/radzen/radzentexteditor.css", "text/css", "", "", "");
|
||||
await LoadSettings();
|
||||
_visible = true;
|
||||
StateHasChanged();
|
||||
|
||||
await _interop.Initialize(_editor.Element);
|
||||
|
||||
if (!string.IsNullOrEmpty(_theme))
|
||||
{
|
||||
ThemeService.SetTheme(_theme);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_background))
|
||||
{
|
||||
var backgroundColor = RadzenEditorDefinitions.TransparentBackgroundColor;
|
||||
switch (_background)
|
||||
{
|
||||
case "Light":
|
||||
backgroundColor = RadzenEditorDefinitions.LightBackgroundColor;
|
||||
break;
|
||||
case "Dark":
|
||||
backgroundColor = RadzenEditorDefinitions.DarkBackgroundColor;
|
||||
break;
|
||||
}
|
||||
await _interop.SetBackgroundColor(_editor.Element, backgroundColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize(string content)
|
||||
{
|
||||
_value = !string.IsNullOrEmpty(content) ? content : string.Empty;
|
||||
DialogService.OnOpen += OnDialogOpened;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (DialogService != null)
|
||||
{
|
||||
DialogService.OnOpen -= OnDialogOpened;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> GetContent()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
return _value;
|
||||
}
|
||||
|
||||
private async Task LoadSettings()
|
||||
{
|
||||
var scope = await EditorSettingService.GetSettingScopeAsync(ModuleState.ModuleId);
|
||||
var editorSetting = scope == 1
|
||||
? await EditorSettingService.LoadSettingsFromModuleAsync(ModuleState.ModuleId)
|
||||
: await EditorSettingService.LoadSettingsFromSiteAsync(PageState.Site.SiteId);
|
||||
|
||||
_theme = editorSetting.Theme;
|
||||
_background = editorSetting.Background;
|
||||
_toolbarItems = editorSetting.ToolbarItems.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
|
||||
_toolbar = SetupToolbarItems();
|
||||
}
|
||||
|
||||
private RenderFragment SetupToolbarItems()
|
||||
{
|
||||
return builder =>
|
||||
{
|
||||
var sequence = 0;
|
||||
foreach (var item in _toolbarItems)
|
||||
{
|
||||
if (RadzenEditorDefinitions.ToolbarItems.ContainsKey(item))
|
||||
{
|
||||
sequence = RadzenEditorDefinitions.ToolbarItems[item](builder, sequence);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private async Task OnExecute(HtmlEditorExecuteEventArgs args)
|
||||
{
|
||||
if (args.CommandName == "InsertImage")
|
||||
{
|
||||
await InsertImage(args.Editor);
|
||||
}
|
||||
else if (args.CommandName == "Settings")
|
||||
{
|
||||
await UpdateSettings(args.Editor);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InsertImage(RadzenHtmlEditor editor)
|
||||
{
|
||||
await editor.SaveSelectionAsync();
|
||||
|
||||
var result = await DialogService.OpenAsync<FileManagerDialog>(Localizer["DialogTitle.SelectImage"], new Dictionary<string, object>
|
||||
{
|
||||
{ "Filters", PageState.Site.ImageFiles }
|
||||
});
|
||||
|
||||
await editor.RestoreSelectionAsync();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
await editor.ExecuteCommandAsync(HtmlEditorCommands.InsertHtml, result);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateSettings(RadzenHtmlEditor editor)
|
||||
{
|
||||
await editor.SaveSelectionAsync();
|
||||
|
||||
var result = await DialogService.OpenAsync<SettingsDialog>(Localizer["Settings"], null, new DialogOptions { Width = "650px" });
|
||||
if (result == true)
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri);
|
||||
}
|
||||
|
||||
await editor.RestoreSelectionAsync();
|
||||
}
|
||||
|
||||
private async void OnDialogOpened(string title, Type componentType, Dictionary<string, object> parameters, DialogOptions options)
|
||||
{
|
||||
await _interop.UpdateDialogLayout(_editor.Element);
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Oqtane.Modules.Controls
|
||||
{
|
||||
public sealed class RadzenEditorDefinitions
|
||||
{
|
||||
public static IStringLocalizer<Oqtane.Modules.Controls.RadzenTextEditor> Localizer { get; internal set; }
|
||||
|
||||
public const string TransparentBackgroundColor = "rgba(0, 0, 0, 0)";
|
||||
|
||||
public const string LightBackgroundColor = "rgba(255, 255, 255, 1)";
|
||||
|
||||
public const string DarkBackgroundColor = "rgba(0, 0, 0, 1)";
|
||||
|
||||
public const string DefaultTheme = "default";
|
||||
|
||||
public const string DefaultBackground = "Default";
|
||||
|
||||
public static readonly IDictionary<string, Func<RenderTreeBuilder, int, int>> ToolbarItems = new Dictionary<string, Func<RenderTreeBuilder, int, int>>()
|
||||
{
|
||||
{ "AlignCenter", (builder, sequence) => CreateFragment(builder, sequence, "AlignCenter", "RadzenHtmlEditorAlignCenter") },
|
||||
{ "AlignLeft", (builder, sequence) => CreateFragment(builder, sequence, "AlignLeft", "RadzenHtmlEditorAlignLeft") },
|
||||
{ "AlignRight", (builder, sequence) => CreateFragment(builder, sequence, "AlignRight", "RadzenHtmlEditorAlignRight") },
|
||||
{ "Background", (builder, sequence) => CreateFragment(builder, sequence, "Background", "RadzenHtmlEditorBackground") },
|
||||
{ "Color", (builder, sequence) => CreateFragment(builder, sequence, "Color", "RadzenHtmlEditorColor") },
|
||||
{ "FontName", (builder, sequence) => CreateFragment(builder, sequence, "FontName", "RadzenHtmlEditorFontName") },
|
||||
{ "FontSize", (builder, sequence) => CreateFragment(builder, sequence, "FontSize", "RadzenHtmlEditorFontSize") },
|
||||
{ "FormatBlock", (builder, sequence) => CreateFragment(builder, sequence, "FormatBlock", "RadzenHtmlEditorFormatBlock") },
|
||||
{ "Indent", (builder, sequence) => CreateFragment(builder, sequence, "Indent", "RadzenHtmlEditorIndent") },
|
||||
{ "InsertImage", (builder, sequence) => CreateFragment(builder, sequence, "InsertImage", "RadzenHtmlEditorCustomTool", "InsertImage", "image") },
|
||||
{ "Italic", (builder, sequence) => CreateFragment(builder, sequence, "Italic", "RadzenHtmlEditorItalic") },
|
||||
{ "Justify", (builder, sequence) => CreateFragment(builder, sequence, "Justify", "RadzenHtmlEditorJustify") },
|
||||
{ "Link", (builder, sequence) => CreateFragment(builder, sequence, "Link", "RadzenHtmlEditorLink") },
|
||||
{ "OrderedList", (builder, sequence) => CreateFragment(builder, sequence, "OrderedList", "RadzenHtmlEditorOrderedList") },
|
||||
{ "Outdent", (builder, sequence) => CreateFragment(builder, sequence, "Outdent", "RadzenHtmlEditorOutdent") },
|
||||
{ "Redo", (builder, sequence) => CreateFragment(builder, sequence, "Redo", "RadzenHtmlEditorRedo") },
|
||||
{ "RemoveFormat", (builder, sequence) => CreateFragment(builder, sequence, "RemoveFormat", "RadzenHtmlEditorRemoveFormat") },
|
||||
{ "Separator", (builder, sequence) => CreateFragment(builder, sequence, "Separator", "RadzenHtmlEditorSeparator") },
|
||||
{ "Source", (builder, sequence) => CreateFragment(builder, sequence, "Source", "RadzenHtmlEditorSource") },
|
||||
{ "StrikeThrough", (builder, sequence) => CreateFragment(builder, sequence, "StrikeThrough", "RadzenHtmlEditorStrikeThrough") },
|
||||
{ "Subscript", (builder, sequence) => CreateFragment(builder, sequence, "Subscript", "RadzenHtmlEditorSubscript") },
|
||||
{ "Superscript", (builder, sequence) => CreateFragment(builder, sequence, "Superscript", "RadzenHtmlEditorSuperscript") },
|
||||
{ "Underline", (builder, sequence) => CreateFragment(builder, sequence, "Underline", "RadzenHtmlEditorUnderline") },
|
||||
{ "Undo", (builder, sequence) => CreateFragment(builder, sequence, "Undo", "RadzenHtmlEditorUndo") },
|
||||
{ "Unlink", (builder, sequence) => CreateFragment(builder, sequence, "Unlink", "RadzenHtmlEditorUnlink") },
|
||||
{ "UnorderedList", (builder, sequence) => CreateFragment(builder, sequence, "UnorderedList", "RadzenHtmlEditorUnorderedList") },
|
||||
};
|
||||
|
||||
public static readonly string DefaultToolbarItems = "Undo,Redo,Separator,FontName,FontSize,FormatBlock,Bold,Italic,Underline,StrikeThrough,Separator,AlignLeft,AlignCenter,AlignRight,Justify,Separator,Indent,Outdent,UnorderedList,OrderedList,Separator,Color,Background,RemoveFormat,Separator,Subscript,Superscript,Separator,Link,Unlink,InsertImage,Separator,Source";
|
||||
|
||||
private static int CreateFragment(RenderTreeBuilder builder, int sequence, string name, string typeName, string commaneName = "", string icon = "")
|
||||
{
|
||||
var fullTypeName = $"Radzen.Blazor.{typeName}, Radzen.Blazor";
|
||||
var type = Type.GetType(fullTypeName);
|
||||
if (type != null)
|
||||
{
|
||||
var title = Localizer[$"{name}.Title"];
|
||||
var placeholder = Localizer[$"{name}.Placeholder"];
|
||||
builder.OpenComponent(sequence++, type);
|
||||
if (!string.IsNullOrEmpty(title) && title != $"{name}.Title" && type.GetProperty("Title") != null)
|
||||
{
|
||||
builder.AddAttribute(sequence++, "Title", title);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(placeholder) && placeholder != $"{name}.Placeholder" && type.GetProperty("Placeholder") != null)
|
||||
{
|
||||
builder.AddAttribute(sequence++, "Placeholder", placeholder);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(commaneName) && type.GetProperty("CommandName") != null)
|
||||
{
|
||||
builder.AddAttribute(sequence++, "CommandName", commaneName);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(icon) && type.GetProperty("Icon") != null)
|
||||
{
|
||||
builder.AddAttribute(sequence++, "Icon", icon);
|
||||
}
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
||||
return sequence;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Modules.Controls
|
||||
{
|
||||
public class RadzenTextEditorInterop
|
||||
{
|
||||
private readonly IJSRuntime _jsRuntime;
|
||||
|
||||
public RadzenTextEditorInterop(IJSRuntime jsRuntime)
|
||||
{
|
||||
_jsRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
public Task Initialize(ElementReference editor)
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeVoidAsync("Oqtane.RadzenTextEditor.initialize", editor);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task SetBackgroundColor(ElementReference editor, string color)
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.RadzenTextEditor.setBackgroundColor",
|
||||
editor, color);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task UpdateDialogLayout(ElementReference editor)
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeVoidAsync("Oqtane.RadzenTextEditor.updateDialogLayout", editor);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace Oqtane.Modules.Controls
|
||||
{
|
||||
public class RadzenEditorSetting
|
||||
{
|
||||
public string Theme { get; set; }
|
||||
|
||||
public string Background { get; set; }
|
||||
|
||||
public string ToolbarItems { get; set; }
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Func<bool?, bool?> OnChange { get; set; }
|
||||
public Action<bool?> OnChange { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
@ -41,35 +41,27 @@
|
||||
break;
|
||||
}
|
||||
|
||||
_value = OnChange(_value);
|
||||
SetImage();
|
||||
OnChange(_value);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetImage()
|
||||
{
|
||||
if (!Disabled)
|
||||
switch (_value)
|
||||
{
|
||||
switch (_value)
|
||||
{
|
||||
case true:
|
||||
_src = "images/checked.png";
|
||||
_title = Localizer["PermissionGranted"];
|
||||
break;
|
||||
case false:
|
||||
_src = "images/unchecked.png";
|
||||
_title = Localizer["PermissionDenied"];
|
||||
break;
|
||||
case null:
|
||||
_src = "images/null.png";
|
||||
_title = string.Empty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_src = "images/disabled.png";
|
||||
_title = Localizer["PermissionDisabled"];
|
||||
case true:
|
||||
_src = "images/checked.png";
|
||||
_title = Localizer["PermissionGranted"];
|
||||
break;
|
||||
case false:
|
||||
_src = "images/unchecked.png";
|
||||
_title = Localizer["PermissionDenied"];
|
||||
break;
|
||||
case null:
|
||||
_src = "images/null.png";
|
||||
_title = string.Empty;
|
||||
break;
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
|
@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Security;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.UI;
|
||||
@ -140,24 +139,14 @@ namespace Oqtane.Modules
|
||||
}
|
||||
}
|
||||
|
||||
// path methods
|
||||
// path method
|
||||
|
||||
public string ModulePath()
|
||||
{
|
||||
return PageState?.Alias.BaseUrl + "/Modules/" + GetType().Namespace + "/";
|
||||
}
|
||||
|
||||
public string StaticAssetPath
|
||||
{
|
||||
get
|
||||
{
|
||||
// requires module to have implemented IModule
|
||||
return PageState?.Alias.BaseUrl + "_content/" + ModuleState.ModuleDefinition?.PackageName + "/";
|
||||
}
|
||||
}
|
||||
|
||||
// fingerprint hash code for static assets
|
||||
|
||||
public string Fingerprint
|
||||
{
|
||||
get
|
||||
@ -166,18 +155,6 @@ namespace Oqtane.Modules
|
||||
}
|
||||
}
|
||||
|
||||
// authorization methods
|
||||
|
||||
public bool IsAuthorizedRole(string roleName)
|
||||
{
|
||||
return UserSecurity.IsAuthorized(PageState.User, roleName);
|
||||
}
|
||||
|
||||
public bool IsAuthorizedPermission(string permissionName)
|
||||
{
|
||||
return UserSecurity.IsAuthorized(PageState.User, permissionName, ModuleState.PermissionList);
|
||||
}
|
||||
|
||||
// url methods
|
||||
|
||||
// navigate url
|
||||
@ -440,9 +417,6 @@ namespace Oqtane.Modules
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
|
||||
|
||||
// token replace methods
|
||||
|
||||
public string ReplaceTokens(string content)
|
||||
{
|
||||
return ReplaceTokens(content, null);
|
||||
@ -526,46 +500,33 @@ namespace Oqtane.Modules
|
||||
};
|
||||
}
|
||||
|
||||
// date conversion methods
|
||||
|
||||
// date methods
|
||||
public DateTime? UtcToLocal(DateTime? datetime)
|
||||
{
|
||||
// Early return if input is null
|
||||
if (datetime == null || datetime.Value == DateTime.MinValue || datetime.Value == DateTime.MaxValue)
|
||||
return datetime;
|
||||
|
||||
string timezoneId = null;
|
||||
|
||||
TimeZoneInfo timezone = null;
|
||||
if (PageState.User != null && !string.IsNullOrEmpty(PageState.User.TimeZoneId))
|
||||
{
|
||||
timezoneId = PageState.User.TimeZoneId;
|
||||
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.User.TimeZoneId);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(PageState.Site.TimeZoneId))
|
||||
{
|
||||
timezoneId = PageState.Site.TimeZoneId;
|
||||
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.Site.TimeZoneId);
|
||||
}
|
||||
|
||||
return Utilities.UtcAsLocalDateTime(datetime, timezoneId);
|
||||
return Utilities.UtcAsLocalDateTime(datetime, timezone);
|
||||
}
|
||||
|
||||
public DateTime? LocalToUtc(DateTime? datetime)
|
||||
{
|
||||
// Early return if input is null
|
||||
if (datetime == null || datetime.Value == DateTime.MinValue || datetime.Value == DateTime.MaxValue)
|
||||
return datetime;
|
||||
|
||||
string timezoneId = null;
|
||||
|
||||
TimeZoneInfo timezone = null;
|
||||
if (PageState.User != null && !string.IsNullOrEmpty(PageState.User.TimeZoneId))
|
||||
{
|
||||
timezoneId = PageState.User.TimeZoneId;
|
||||
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.User.TimeZoneId);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(PageState.Site.TimeZoneId))
|
||||
{
|
||||
timezoneId = PageState.Site.TimeZoneId;
|
||||
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.Site.TimeZoneId);
|
||||
}
|
||||
|
||||
return Utilities.LocalDateAndTimeAsUtc(datetime, timezoneId);
|
||||
return Utilities.LocalDateAndTimeAsUtc(datetime, timezone);
|
||||
}
|
||||
|
||||
// logging methods
|
||||
|
@ -4,7 +4,7 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>6.2.0</Version>
|
||||
<Version>6.1.3</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -12,7 +12,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.3</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
@ -22,17 +22,22 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.8" />
|
||||
<PackageReference Include="Radzen.Blazor" Version="7.3.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="Installer\Controls\AzureSqlConfig.razor">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PublishTrimmed>false</PublishTrimmed>
|
||||
<BlazorEnableCompression>false</BlazorEnableCompression>
|
||||
|
@ -183,7 +183,4 @@
|
||||
<data name="Refresh.Text" xml:space="preserve">
|
||||
<value>Refresh</value>
|
||||
</data>
|
||||
<data name="Message.Job.Disabled" xml:space="preserve">
|
||||
<value>The job cannot be started while in the disabled state.</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
@ -133,7 +133,7 @@
|
||||
<value>External Login Could Not Be Linked. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="Error.Login.Fail" xml:space="preserve">
|
||||
<value>Login Failed. Please Remember That Passwords Are Case Sensitive. If You Have Attempted To Sign In Multiple Times Unsuccessfully, Your Account Will Be Locked Out For A Period Of Time. Note That New User Accounts Often Require Email Address Verification So You May Wish To Check Your Email For A Notification Containing Further Instructions.</value>
|
||||
<value>Login Failed. Please Remember That Passwords Are Case Sensitive. If You Have Attempted To Sign In Multiple Times Unsuccessfully, Your Account Will Be Locked Out For A Period Of Time. Note That User Accounts Often Require Email Address Verification So You May Wish To Check Your Email For A Notification.</value>
|
||||
</data>
|
||||
<data name="Message.Required.UserInfo" xml:space="preserve">
|
||||
<value>Please Provide All Required Fields</value>
|
||||
|
@ -126,9 +126,6 @@
|
||||
<data name="Success.Module.Download" xml:space="preserve">
|
||||
<value>Module Package Downloaded Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||
</data>
|
||||
<data name="Success.Module.Upload" xml:space="preserve">
|
||||
<value>Module Package Uploaded Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||
</data>
|
||||
<data name="Error.Module.Download" xml:space="preserve">
|
||||
<value>Error Downloading Module</value>
|
||||
</data>
|
||||
|
@ -157,7 +157,7 @@
|
||||
<value>The default value for this profile item</value>
|
||||
</data>
|
||||
<data name="Options.HelpText" xml:space="preserve">
|
||||
<value>A comma delimited list of options. Options can contain a key and value if they are seperated by a colon (ie. key:value). You can also dynamically load your options from custom Settings (ie. 'EntityName:Countries').</value>
|
||||
<value>A comma delimited list of options the user can select from</value>
|
||||
</data>
|
||||
<data name="Required.HelpText" xml:space="preserve">
|
||||
<value>Should a user be required to provide a value for this profile item?</value>
|
||||
|
@ -1,156 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="SettingName.Text" xml:space="preserve">
|
||||
<value>Name:</value>
|
||||
</data>
|
||||
<data name="SettingName.HelpText" xml:space="preserve">
|
||||
<value>Setting Name</value>
|
||||
</data>
|
||||
<data name="EntityId.HelpText" xml:space="preserve">
|
||||
<value>Select an existing Id or input a new Id. For Entities which are global such as master data, use the Id value '-1'.</value>
|
||||
</data>
|
||||
<data name="EntityName.HelpText" xml:space="preserve">
|
||||
<value>Select an existing Entity or input a custom Entity. Custom Entities with a prefix of 'Master:' will be stored in the master database.</value>
|
||||
</data>
|
||||
<data name="EntityId.Text" xml:space="preserve">
|
||||
<value>Id:</value>
|
||||
</data>
|
||||
<data name="EntityName.Text" xml:space="preserve">
|
||||
<value>Entity:</value>
|
||||
</data>
|
||||
<data name="Error.SaveSetting" xml:space="preserve">
|
||||
<value>Error Saving Setting</value>
|
||||
</data>
|
||||
<data name="Message.InfoRequired" xml:space="preserve">
|
||||
<value>Please Provide All Required Information</value>
|
||||
</data>
|
||||
<data name="SettingValue.Text" xml:space="preserve">
|
||||
<value>Value:</value>
|
||||
</data>
|
||||
<data name="SettingValue.HelpText" xml:space="preserve">
|
||||
<value>Setting Value</value>
|
||||
</data>
|
||||
<data name="IsPrivate.Text" xml:space="preserve">
|
||||
<value>Private?</value>
|
||||
</data>
|
||||
<data name="IsPrivate.HelpText" xml:space="preserve">
|
||||
<value>Indicates if this setting is private ie. if it should only be maintained on the server and not sent to the client</value>
|
||||
</data>
|
||||
</root>
|
@ -1,159 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="SettingName.Text" xml:space="preserve">
|
||||
<value>Name:</value>
|
||||
</data>
|
||||
<data name="SettingName.HelpText" xml:space="preserve">
|
||||
<value>Setting Name</value>
|
||||
</data>
|
||||
<data name="EntityId.HelpText" xml:space="preserve">
|
||||
<value>Entity Id</value>
|
||||
</data>
|
||||
<data name="EntityName.HelpText" xml:space="preserve">
|
||||
<value>Entity Name</value>
|
||||
</data>
|
||||
<data name="EntityId.Text" xml:space="preserve">
|
||||
<value>Id:</value>
|
||||
</data>
|
||||
<data name="EntityName.Text" xml:space="preserve">
|
||||
<value>Entity:</value>
|
||||
</data>
|
||||
<data name="Error.LoadSetting" xml:space="preserve">
|
||||
<value>Error Loading Setting</value>
|
||||
</data>
|
||||
<data name="Error.SaveSetting" xml:space="preserve">
|
||||
<value>Error Saving Setting</value>
|
||||
</data>
|
||||
<data name="Message.InfoRequired" xml:space="preserve">
|
||||
<value>Please Provide All Required Information</value>
|
||||
</data>
|
||||
<data name="SettingValue.Text" xml:space="preserve">
|
||||
<value>Value:</value>
|
||||
</data>
|
||||
<data name="SettingValue.HelpText" xml:space="preserve">
|
||||
<value>Setting Value</value>
|
||||
</data>
|
||||
<data name="IsPrivate.Text" xml:space="preserve">
|
||||
<value>Private?</value>
|
||||
</data>
|
||||
<data name="IsPrivate.HelpText" xml:space="preserve">
|
||||
<value>Indicates if this setting is private ie. if it should only be maintained on the server and not sent to the client</value>
|
||||
</data>
|
||||
</root>
|
@ -1,141 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Settings.Text" xml:space="preserve">
|
||||
<value>Settings:</value>
|
||||
</data>
|
||||
<data name="Settings.HelpText" xml:space="preserve">
|
||||
<value>Provide settings in comma delimited format using the column template specified</value>
|
||||
</data>
|
||||
<data name="Import" xml:space="preserve">
|
||||
<value>Import</value>
|
||||
</data>
|
||||
<data name="Message.Import.Success" xml:space="preserve">
|
||||
<value>Setting Import Successful</value>
|
||||
</data>
|
||||
<data name="Message.Import.Validation" xml:space="preserve">
|
||||
<value>You Must Provide Settings To Import</value>
|
||||
</data>
|
||||
<data name="Message.Import.Failure" xml:space="preserve">
|
||||
<value>Setting Import Failed. Please Review Your Event Log For More Detailed Information.</value>
|
||||
</data>
|
||||
<data name="Error.Import" xml:space="preserve">
|
||||
<value>Error Importing Settings</value>
|
||||
</data>
|
||||
</root>
|
@ -1,153 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Confirm.DeleteSetting" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Delete The {0} Setting?</value>
|
||||
</data>
|
||||
<data name="Error.DeleteSetting" xml:space="preserve">
|
||||
<value>Error Deleting Setting</value>
|
||||
</data>
|
||||
<data name="AddSetting.Text" xml:space="preserve">
|
||||
<value>Add Setting</value>
|
||||
</data>
|
||||
<data name="DeleteSetting.Header" xml:space="preserve">
|
||||
<value>Delete Setting</value>
|
||||
</data>
|
||||
<data name="DeleteSetting.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="EditSetting.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="Select Entity" xml:space="preserve">
|
||||
<value>Select Entity</value>
|
||||
</data>
|
||||
<data name="Select Id" xml:space="preserve">
|
||||
<value>Select Id</value>
|
||||
</data>
|
||||
<data name="Name" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="Value" xml:space="preserve">
|
||||
<value>Value</value>
|
||||
</data>
|
||||
<data name="Import.SettingsText" xml:space="preserve">
|
||||
<value>Import</value>
|
||||
</data>
|
||||
</root>
|
@ -192,8 +192,8 @@
|
||||
<data name="Port.HelpText" xml:space="preserve">
|
||||
<value>Enter the port number for the SMTP server. Please note this field is required if you provide a host name.</value>
|
||||
</data>
|
||||
<data name="SmtpSSL.HelpText" xml:space="preserve">
|
||||
<value>Specify the type of SSL connection for your SMTP server</value>
|
||||
<data name="UseSsl.HelpText" xml:space="preserve">
|
||||
<value>Specify if SSL is required for your SMTP server</value>
|
||||
</data>
|
||||
<data name="SmtpUsername.HelpText" xml:space="preserve">
|
||||
<value>Enter the username for your SMTP account</value>
|
||||
@ -202,7 +202,7 @@
|
||||
<value>Enter the password for your SMTP account</value>
|
||||
</data>
|
||||
<data name="SmtpSender.HelpText" xml:space="preserve">
|
||||
<value>Enter the email address which emails will be sent from. Please note that this email address usually needs to be authorized with the SMTP server.</value>
|
||||
<value>Enter the email which emails will be sent from. Please note that this email address may need to be authorized with the SMTP server.</value>
|
||||
</data>
|
||||
<data name="EnablePWA.HelpText" xml:space="preserve">
|
||||
<value>Select whether you would like this site to be available as a Progressive Web Application (PWA)</value>
|
||||
@ -240,8 +240,8 @@
|
||||
<data name="Port.Text" xml:space="preserve">
|
||||
<value>Port: </value>
|
||||
</data>
|
||||
<data name="SmtpSSL.Text" xml:space="preserve">
|
||||
<value>SSL Options:</value>
|
||||
<data name="UseSsl.Text" xml:space="preserve">
|
||||
<value>SSL Enabled: </value>
|
||||
</data>
|
||||
<data name="SmtpUsername.Text" xml:space="preserve">
|
||||
<value>Username: </value>
|
||||
@ -372,10 +372,10 @@
|
||||
<data name="PageContent.Heading" xml:space="preserve">
|
||||
<value>Page Content</value>
|
||||
</data>
|
||||
<data name="SmtpEnabled.HelpText" xml:space="preserve">
|
||||
<data name="SMTPEnabled.HelpText" xml:space="preserve">
|
||||
<value>Specify if SMTP is enabled for this site</value>
|
||||
</data>
|
||||
<data name="SmtpEnabled.Text" xml:space="preserve">
|
||||
<data name="SMTPEnabled.Text" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
<data name="Version.HelpText" xml:space="preserve">
|
||||
@ -453,55 +453,4 @@
|
||||
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||
<value>The default time zone for the site</value>
|
||||
</data>
|
||||
<data name="Basic" xml:space="preserve">
|
||||
<value>Basic</value>
|
||||
</data>
|
||||
<data name="OAuth2" xml:space="preserve">
|
||||
<value>OAuth 2.0 (OAuth2)</value>
|
||||
</data>
|
||||
<data name="SmtpAuthentication.Text" xml:space="preserve">
|
||||
<value>Authentication:</value>
|
||||
</data>
|
||||
<data name="SmtpAuthentication.HelpText" xml:space="preserve">
|
||||
<value>Specify the SMTP authentication type</value>
|
||||
</data>
|
||||
<data name="SmtpClientID.Text" xml:space="preserve">
|
||||
<value>Client ID:</value>
|
||||
</data>
|
||||
<data name="SmtpClientID.HelpText" xml:space="preserve">
|
||||
<value>The Client ID for the SMTP provider</value>
|
||||
</data>
|
||||
<data name="SmtpClientSecret.Text" xml:space="preserve">
|
||||
<value>Client Secret:</value>
|
||||
</data>
|
||||
<data name="SmtpClientSecret.HelpText" xml:space="preserve">
|
||||
<value>The Client Secret for the SMTP provider</value>
|
||||
</data>
|
||||
<data name="SmtpScopes.Text" xml:space="preserve">
|
||||
<value>Scopes:</value>
|
||||
</data>
|
||||
<data name="SmtpScopes.HelpText" xml:space="preserve">
|
||||
<value>A list of Scopes for the SMTP provider (separated by commas)</value>
|
||||
</data>
|
||||
<data name="SmtpAuthority.Text" xml:space="preserve">
|
||||
<value>Authority Url:</value>
|
||||
</data>
|
||||
<data name="SmtpAuthority.HelpText" xml:space="preserve">
|
||||
<value>The Authority Url for the SMTP provider</value>
|
||||
</data>
|
||||
<data name="None" xml:space="preserve">
|
||||
<value>None</value>
|
||||
</data>
|
||||
<data name="Auto" xml:space="preserve">
|
||||
<value>Automatic</value>
|
||||
</data>
|
||||
<data name="StartTls" xml:space="preserve">
|
||||
<value>Upgrade To TLS</value>
|
||||
</data>
|
||||
<data name="SslOnConnect" xml:space="preserve">
|
||||
<value>Require SSL/TLS</value>
|
||||
</data>
|
||||
<data name="StartTlsWhenAvailable" xml:space="preserve">
|
||||
<value>Use TLS When Available</value>
|
||||
</data>
|
||||
</root>
|
@ -126,9 +126,6 @@
|
||||
<data name="Success.Theme.Download" xml:space="preserve">
|
||||
<value>Theme Package Downloaded Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||
</data>
|
||||
<data name="Success.Theme.Upload" xml:space="preserve">
|
||||
<value>Theme Package Uploaded Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||
</data>
|
||||
<data name="Error.Theme.Download" xml:space="preserve">
|
||||
<value>Error Downloading Theme</value>
|
||||
</data>
|
||||
|
@ -156,6 +156,9 @@
|
||||
<data name="Enabled" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
<data name="Assign" xml:space="preserve">
|
||||
<value>Assign</value>
|
||||
</data>
|
||||
<data name="Synchronize" xml:space="preserve">
|
||||
<value>Check For Updates</value>
|
||||
</data>
|
||||
|
@ -147,6 +147,9 @@
|
||||
<data name="Message.User.NoLogIn" xml:space="preserve">
|
||||
<value>Current User Is Not Logged In</value>
|
||||
</data>
|
||||
<data name="Message.User.NoEmail" xml:space="preserve">
|
||||
<value>You Must Provide An Email Address For Your User Account</value>
|
||||
</data>
|
||||
<data name="Error.Profile.Load" xml:space="preserve">
|
||||
<value>Error Loading User Profile</value>
|
||||
</data>
|
||||
|
@ -162,10 +162,4 @@
|
||||
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||
<value>The user's time zone</value>
|
||||
</data>
|
||||
<data name="Confirmed.Text" xml:space="preserve">
|
||||
<value>Verified?</value>
|
||||
</data>
|
||||
<data name="Confirmed.HelpText" xml:space="preserve">
|
||||
<value>Indicates if the user's email is verified</value>
|
||||
</data>
|
||||
</root>
|
@ -217,7 +217,7 @@
|
||||
<value>The user's time zone</value>
|
||||
</data>
|
||||
<data name="Confirmed.Text" xml:space="preserve">
|
||||
<value>Verified?</value>
|
||||
<value>Confirmed?</value>
|
||||
</data>
|
||||
<data name="Confirmed.HelpText" xml:space="preserve">
|
||||
<value>Indicates if the user's email is verified</value>
|
||||
|
@ -370,13 +370,7 @@
|
||||
<value>Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out.</value>
|
||||
</data>
|
||||
<data name="TwoFactor.Text" xml:space="preserve">
|
||||
<value>Two Factor Authentication?</value>
|
||||
</data>
|
||||
<data name="RequireConfirmedEmail.HelpText" xml:space="preserve">
|
||||
<value>Do you want to require registered users to verify their email address before they are allowed to log in?</value>
|
||||
</data>
|
||||
<data name="RequireConfirmedEmail.Text" xml:space="preserve">
|
||||
<value>Require Verified Email?</value>
|
||||
<value>Two Factor?</value>
|
||||
</data>
|
||||
<data name="Disabled" xml:space="preserve">
|
||||
<value>Disabled</value>
|
||||
@ -508,17 +502,11 @@
|
||||
<value>Info</value>
|
||||
</data>
|
||||
<data name="OAuth2" xml:space="preserve">
|
||||
<value>OAuth 2.0 (OAuth2)</value>
|
||||
<value>OAuth 2.0</value>
|
||||
</data>
|
||||
<data name="OIDC" xml:space="preserve">
|
||||
<value>OpenID Connect (OIDC)</value>
|
||||
</data>
|
||||
<data name="RequireNonce.Text" xml:space="preserve">
|
||||
<value>Require Nonce?</value>
|
||||
</data>
|
||||
<data name="RequireNonce.HelpText" xml:space="preserve">
|
||||
<value>Specify if Nonce validation is required for the ID token (the default is true)</value>
|
||||
</data>
|
||||
<data name="SaveTokens.Text" xml:space="preserve">
|
||||
<value>Save Tokens?</value>
|
||||
</data>
|
||||
@ -543,16 +531,4 @@
|
||||
<data name="AllowHostRole.HelpText" xml:space="preserve">
|
||||
<value>Indicate if host roles are supported from the identity provider. Please use caution with this option as it allows the host user to administrate every site within your installation.</value>
|
||||
</data>
|
||||
<data name="Active Users" xml:space="preserve">
|
||||
<value>Active Users</value>
|
||||
</data>
|
||||
<data name="Deleted Users" xml:space="preserve">
|
||||
<value>Deleted Users</value>
|
||||
</data>
|
||||
<data name="CookieDomain.Text" xml:space="preserve">
|
||||
<value>Cookie Domain:</value>
|
||||
</data>
|
||||
<data name="CookieDomain.HelpText" xml:space="preserve">
|
||||
<value>If you would like to share cookies across subdomains you will need to specify a root domain with a leading dot (ie. '.example.com')</value>
|
||||
</data>
|
||||
</root>
|
@ -1,219 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Background" xml:space="preserve">
|
||||
<value>Editor Background:</value>
|
||||
</data>
|
||||
<data name="Close" xml:space="preserve">
|
||||
<value>Close</value>
|
||||
</data>
|
||||
<data name="Dark" xml:space="preserve">
|
||||
<value>Dark</value>
|
||||
</data>
|
||||
<data name="Default" xml:space="preserve">
|
||||
<value>Default</value>
|
||||
</data>
|
||||
<data name="DialogTitle.SelectImage" xml:space="preserve">
|
||||
<value>Select Image</value>
|
||||
</data>
|
||||
<data name="FontName.Placeholder" xml:space="preserve">
|
||||
<value>Font</value>
|
||||
</data>
|
||||
<data name="FontName.Title" xml:space="preserve">
|
||||
<value>Font Name</value>
|
||||
</data>
|
||||
<data name="FontSize.Placeholder" xml:space="preserve">
|
||||
<value>Size</value>
|
||||
</data>
|
||||
<data name="FontSize.Title" xml:space="preserve">
|
||||
<value>Font Size</value>
|
||||
</data>
|
||||
<data name="FormatBlock.Placeholder" xml:space="preserve">
|
||||
<value>Format</value>
|
||||
</data>
|
||||
<data name="FormatBlock.Title" xml:space="preserve">
|
||||
<value>Format Block</value>
|
||||
</data>
|
||||
<data name="theme.humanistic" xml:space="preserve">
|
||||
<value>Humanistic</value>
|
||||
</data>
|
||||
<data name="theme.humanistic-dark" xml:space="preserve">
|
||||
<value>Humanistic Dark</value>
|
||||
</data>
|
||||
<data name="InsertImage" xml:space="preserve">
|
||||
<value>Insert Image</value>
|
||||
</data>
|
||||
<data name="Light" xml:space="preserve">
|
||||
<value>Light</value>
|
||||
</data>
|
||||
<data name="theme.material" xml:space="preserve">
|
||||
<value>Material</value>
|
||||
</data>
|
||||
<data name="theme.material-dark" xml:space="preserve">
|
||||
<value>Material Dark</value>
|
||||
</data>
|
||||
<data name="Message.Require.Image" xml:space="preserve">
|
||||
<value>You Must Select An Image To Insert</value>
|
||||
</data>
|
||||
<data name="Module" xml:space="preserve">
|
||||
<value>Module</value>
|
||||
</data>
|
||||
<data name="Placeholder" xml:space="preserve">
|
||||
<value>Enter Your Content...</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Scope" xml:space="preserve">
|
||||
<value>Scope:</value>
|
||||
</data>
|
||||
<data name="Site" xml:space="preserve">
|
||||
<value>Site</value>
|
||||
</data>
|
||||
<data name="theme.software" xml:space="preserve">
|
||||
<value>Software</value>
|
||||
</data>
|
||||
<data name="theme.software-dark" xml:space="preserve">
|
||||
<value>Software Dark</value>
|
||||
</data>
|
||||
<data name="theme.standard" xml:space="preserve">
|
||||
<value>Standard</value>
|
||||
</data>
|
||||
<data name="theme.standard-dark" xml:space="preserve">
|
||||
<value>Standard Dark</value>
|
||||
</data>
|
||||
<data name="Theme" xml:space="preserve">
|
||||
<value>Theme:</value>
|
||||
</data>
|
||||
<data name="theme.dark" xml:space="preserve">
|
||||
<value>Dark</value>
|
||||
</data>
|
||||
<data name="theme.default" xml:space="preserve">
|
||||
<value>Default</value>
|
||||
</data>
|
||||
<data name="Toolbar" xml:space="preserve">
|
||||
<value>Toolbar Items:</value>
|
||||
</data>
|
||||
<data name="Add" xml:space="preserve">
|
||||
<value>Add</value>
|
||||
</data>
|
||||
<data name="Reset" xml:space="preserve">
|
||||
<value>Reset</value>
|
||||
</data>
|
||||
</root>
|
@ -123,7 +123,4 @@
|
||||
<data name="PermissionDenied" xml:space="preserve">
|
||||
<value>Permission Denied</value>
|
||||
</data>
|
||||
<data name="PermissionDisabled" xml:space="preserve">
|
||||
<value>Permission Disabled</value>
|
||||
</data>
|
||||
</root>
|
@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
@ -8,46 +8,6 @@ using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to retrieve and store <see cref="Alias"/> information.
|
||||
/// </summary>
|
||||
public interface IAliasService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all aliases in the system
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<Alias>> GetAliasesAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Get a single alias
|
||||
/// </summary>
|
||||
/// <param name="aliasId">The <see cref="Oqtane.Models.Alias"/> ID, not to be confused with a <see cref="Oqtane.Models.Site"/> ID</param>
|
||||
/// <returns></returns>
|
||||
Task<Alias> GetAliasAsync(int aliasId);
|
||||
|
||||
/// <summary>
|
||||
/// Save another <see cref="Oqtane.Models.Alias"/> in the DB. It must already contain all the information incl. <see cref="Oqtane.Models.Tenant"/> it belongs to.
|
||||
/// </summary>
|
||||
/// <param name="alias">An <see cref="Oqtane.Models.Alias"/> to add.</param>
|
||||
/// <returns></returns>
|
||||
Task<Alias> AddAliasAsync(Alias alias);
|
||||
|
||||
/// <summary>
|
||||
/// Update an <see cref="Oqtane.Models.Alias"/> in the DB. Make sure the object is correctly filled, as it must update an existing record.
|
||||
/// </summary>
|
||||
/// <param name="alias">The <see cref="Oqtane.Models.Alias"/> to update.</param>
|
||||
/// <returns></returns>
|
||||
Task<Alias> UpdateAliasAsync(Alias alias);
|
||||
|
||||
/// <summary>
|
||||
/// Remove an <see cref="Oqtane.Models.Alias"/> from the DB.
|
||||
/// </summary>
|
||||
/// <param name="aliasId">The Alias ID, not to be confused with a Site ID.</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAliasAsync(int aliasId);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IAliasService" />
|
||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||
public class AliasService : ServiceBase, IAliasService
|
||||
|
@ -1,46 +1,13 @@
|
||||
using Oqtane.Models;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using System;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Shared;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to retrieve cookie consent information.
|
||||
/// </summary>
|
||||
public interface ICookieConsentService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get cookie consent bar actioned status
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<bool> IsActionedAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Get cookie consent status
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<bool> CanTrackAsync(bool optOut);
|
||||
|
||||
/// <summary>
|
||||
/// create actioned cookie
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<string> CreateActionedCookieAsync();
|
||||
|
||||
/// <summary>
|
||||
/// create consent cookie
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<string> CreateConsentCookieAsync();
|
||||
|
||||
/// <summary>
|
||||
/// widhdraw consent cookie
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<string> WithdrawConsentCookieAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ICookieConsentService" />
|
||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||
public class CookieConsentService : ServiceBase, ICookieConsentService
|
||||
|
@ -8,18 +8,6 @@ using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to retrieve <see cref="Database"/> information.
|
||||
/// </summary>
|
||||
public interface IDatabaseService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a list of databases
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<Database>> GetDatabasesAsync();
|
||||
}
|
||||
|
||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||
public class DatabaseService : ServiceBase, IDatabaseService
|
||||
{
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
@ -9,103 +10,6 @@ using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to get / create / upload / download files.
|
||||
/// </summary>
|
||||
public interface IFileService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all <see cref="File"/>s in the specified Folder
|
||||
/// </summary>
|
||||
/// <param name="folderId">The folder ID</param>
|
||||
/// <returns></returns>
|
||||
Task<List<File>> GetFilesAsync(int folderId);
|
||||
|
||||
/// <summary>
|
||||
/// Get all <see cref="File"/>s in the specified folder.
|
||||
/// </summary>
|
||||
/// <param name="folder">
|
||||
/// The folder path relative to where the files are stored.
|
||||
/// TODO: todoc verify exactly from where the folder path must start
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task<List<File>> GetFilesAsync(string folder);
|
||||
|
||||
/// <summary>
|
||||
/// Get one <see cref="File"/>
|
||||
/// </summary>
|
||||
/// <param name="fileId"></param>
|
||||
/// <returns></returns>
|
||||
Task<File> GetFileAsync(int fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="File"/> based on the <see cref="Folder"/> and file name.
|
||||
/// </summary>
|
||||
/// <param name="folderId">Reference to the <see cref="Folder"/></param>
|
||||
/// <param name="name">name of the file
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task<File> GetFileAsync(int folderId, string name);
|
||||
|
||||
/// <summary>
|
||||
/// Add / store a <see cref="File"/> record.
|
||||
/// This does not contain the file contents.
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
Task<File> AddFileAsync(File file);
|
||||
|
||||
/// <summary>
|
||||
/// Update a <see cref="File"/> record.
|
||||
/// Use this for rename a file or change some attributes.
|
||||
/// This does not contain the file contents.
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
Task<File> UpdateFileAsync(File file);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a <see cref="File"/>
|
||||
/// </summary>
|
||||
/// <param name="fileId"></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteFileAsync(int fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Upload a file from a URL to a <see cref="Folder"/>
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="folderId"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
Task<File> UploadFileAsync(string url, int folderId, string name);
|
||||
|
||||
/// <summary>
|
||||
/// Get / download a file (the body).
|
||||
/// </summary>
|
||||
/// <param name="fileId">Reference to a <see cref="File"/></param>
|
||||
/// <returns>The bytes of the file</returns>
|
||||
Task<byte[]> DownloadFileAsync(int fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a list of files from a <see cref="Site"/> and <see cref="Folder"/>
|
||||
/// </summary>
|
||||
/// <param name="siteId">Reference to the <see cref="Site"/></param>
|
||||
/// <param name="folderPath">Path of the folder
|
||||
/// TODO: todoc verify exactly from where the folder path must start
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task<List<File>> GetFilesAsync(int siteId, string folderPath);
|
||||
|
||||
/// <summary>
|
||||
/// Unzips the contents of a zip file
|
||||
/// </summary>
|
||||
/// <param name="fileId">Reference to the <see cref="File"/></param>
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task UnzipFileAsync(int fileId);
|
||||
}
|
||||
|
||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||
public class FileService : ServiceBase, IFileService
|
||||
{
|
||||
|
@ -9,58 +9,6 @@ using Oqtane.Documentation;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to get / create / modify <see cref="Folder"/> objects.
|
||||
/// </summary>
|
||||
public interface IFolderService
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve root folders of a <see cref="Site"/>
|
||||
/// </summary>
|
||||
/// <param name="siteId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<Folder>> GetFoldersAsync(int siteId);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the information of one <see cref="Folder"/>
|
||||
/// </summary>
|
||||
/// <param name="folderId"></param>
|
||||
/// <returns></returns>
|
||||
Task<Folder> GetFolderAsync(int folderId);
|
||||
|
||||
/// <summary>
|
||||
/// Create one Folder using a <see cref="Folder"/> object.
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
/// <returns></returns>
|
||||
Task<Folder> AddFolderAsync(Folder folder);
|
||||
|
||||
/// <summary>
|
||||
/// Update the information about a <see cref="Folder"/>
|
||||
/// Use this to rename the folder etc.
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
/// <returns></returns>
|
||||
Task<Folder> UpdateFolderAsync(Folder folder);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a <see cref="Folder"/>
|
||||
/// </summary>
|
||||
/// <param name="folderId">Reference to a <see cref="Folder"/></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteFolderAsync(int folderId);
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="Folder"/> of a <see cref="Site"/> based on the path.
|
||||
/// </summary>
|
||||
/// <param name="siteId">Reference to the <see cref="Site"/></param>
|
||||
/// <param name="folderPath">Path of the folder
|
||||
/// TODO: todoc verify exactly from where the folder path must start
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task<Folder> GetFolderAsync(int siteId, [NotNull] string folderPath);
|
||||
}
|
||||
|
||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||
public class FolderService : ServiceBase, IFolderService
|
||||
{
|
||||
|
@ -10,38 +10,6 @@ using System.Linq;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to manage (install master database / upgrade version / etc.) the installation
|
||||
/// </summary>
|
||||
public interface IInstallationService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a status/message object with the current installation state
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<Installation> IsInstalled();
|
||||
|
||||
/// <summary>
|
||||
/// Starts the installation process
|
||||
/// </summary>
|
||||
/// <param name="config">connectionString, database type, alias etc.</param>
|
||||
/// <returns>internal status/message object</returns>
|
||||
Task<Installation> Install(InstallConfig config);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the upgrade process
|
||||
/// </summary>
|
||||
/// <param name="backup">indicates if files should be backed up during upgrade</param>
|
||||
/// <returns>internal status/message object</returns>
|
||||
Task<Installation> Upgrade(bool backup);
|
||||
|
||||
/// <summary>
|
||||
/// Restarts the installation
|
||||
/// </summary>
|
||||
/// <returns>internal status/message object</returns>
|
||||
Task RestartAsync();
|
||||
}
|
||||
|
||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||
public class InstallationService : ServiceBase, IInstallationService
|
||||
{
|
||||
|
47
Oqtane.Client/Services/Interfaces/IAliasService.cs
Normal file
47
Oqtane.Client/Services/Interfaces/IAliasService.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using Oqtane.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to retrieve and store <see cref="Alias"/> information.
|
||||
/// </summary>
|
||||
public interface IAliasService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all aliases in the system
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<Alias>> GetAliasesAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Get a single alias
|
||||
/// </summary>
|
||||
/// <param name="aliasId">The <see cref="Oqtane.Models.Alias"/> ID, not to be confused with a <see cref="Oqtane.Models.Site"/> ID</param>
|
||||
/// <returns></returns>
|
||||
Task<Alias> GetAliasAsync(int aliasId);
|
||||
|
||||
/// <summary>
|
||||
/// Save another <see cref="Oqtane.Models.Alias"/> in the DB. It must already contain all the information incl. <see cref="Oqtane.Models.Tenant"/> it belongs to.
|
||||
/// </summary>
|
||||
/// <param name="alias">An <see cref="Oqtane.Models.Alias"/> to add.</param>
|
||||
/// <returns></returns>
|
||||
Task<Alias> AddAliasAsync(Alias alias);
|
||||
|
||||
/// <summary>
|
||||
/// Update an <see cref="Oqtane.Models.Alias"/> in the DB. Make sure the object is correctly filled, as it must update an existing record.
|
||||
/// </summary>
|
||||
/// <param name="alias">The <see cref="Oqtane.Models.Alias"/> to update.</param>
|
||||
/// <returns></returns>
|
||||
Task<Alias> UpdateAliasAsync(Alias alias);
|
||||
|
||||
/// <summary>
|
||||
/// Remove an <see cref="Oqtane.Models.Alias"/> from the DB.
|
||||
/// </summary>
|
||||
/// <param name="aliasId">The Alias ID, not to be confused with a Site ID.</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteAliasAsync(int aliasId);
|
||||
}
|
||||
}
|
42
Oqtane.Client/Services/Interfaces/ICookieConsentService.cs
Normal file
42
Oqtane.Client/Services/Interfaces/ICookieConsentService.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using Oqtane.Models;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to retrieve cookie consent information.
|
||||
/// </summary>
|
||||
public interface ICookieConsentService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get cookie consent bar actioned status
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<bool> IsActionedAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Get cookie consent status
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<bool> CanTrackAsync(bool optOut);
|
||||
|
||||
/// <summary>
|
||||
/// create actioned cookie
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<string> CreateActionedCookieAsync();
|
||||
|
||||
/// <summary>
|
||||
/// create consent cookie
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<string> CreateConsentCookieAsync();
|
||||
|
||||
/// <summary>
|
||||
/// widhdraw consent cookie
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<string> WithdrawConsentCookieAsync();
|
||||
}
|
||||
}
|
18
Oqtane.Client/Services/Interfaces/IDatabaseService.cs
Normal file
18
Oqtane.Client/Services/Interfaces/IDatabaseService.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to retrieve <see cref="Database"/> information.
|
||||
/// </summary>
|
||||
public interface IDatabaseService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a list of databases
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<Database>> GetDatabasesAsync();
|
||||
}
|
||||
}
|
104
Oqtane.Client/Services/Interfaces/IFileService.cs
Normal file
104
Oqtane.Client/Services/Interfaces/IFileService.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to get / create / upload / download files.
|
||||
/// </summary>
|
||||
public interface IFileService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all <see cref="File"/>s in the specified Folder
|
||||
/// </summary>
|
||||
/// <param name="folderId">The folder ID</param>
|
||||
/// <returns></returns>
|
||||
Task<List<File>> GetFilesAsync(int folderId);
|
||||
|
||||
/// <summary>
|
||||
/// Get all <see cref="File"/>s in the specified folder.
|
||||
/// </summary>
|
||||
/// <param name="folder">
|
||||
/// The folder path relative to where the files are stored.
|
||||
/// TODO: todoc verify exactly from where the folder path must start
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task<List<File>> GetFilesAsync(string folder);
|
||||
|
||||
/// <summary>
|
||||
/// Get one <see cref="File"/>
|
||||
/// </summary>
|
||||
/// <param name="fileId"></param>
|
||||
/// <returns></returns>
|
||||
Task<File> GetFileAsync(int fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="File"/> based on the <see cref="Folder"/> and file name.
|
||||
/// </summary>
|
||||
/// <param name="folderId">Reference to the <see cref="Folder"/></param>
|
||||
/// <param name="name">name of the file
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task<File> GetFileAsync(int folderId, string name);
|
||||
|
||||
/// <summary>
|
||||
/// Add / store a <see cref="File"/> record.
|
||||
/// This does not contain the file contents.
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
Task<File> AddFileAsync(File file);
|
||||
|
||||
/// <summary>
|
||||
/// Update a <see cref="File"/> record.
|
||||
/// Use this for rename a file or change some attributes.
|
||||
/// This does not contain the file contents.
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
Task<File> UpdateFileAsync(File file);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a <see cref="File"/>
|
||||
/// </summary>
|
||||
/// <param name="fileId"></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteFileAsync(int fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Upload a file from a URL to a <see cref="Folder"/>
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="folderId"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
Task<File> UploadFileAsync(string url, int folderId, string name);
|
||||
|
||||
/// <summary>
|
||||
/// Get / download a file (the body).
|
||||
/// </summary>
|
||||
/// <param name="fileId">Reference to a <see cref="File"/></param>
|
||||
/// <returns>The bytes of the file</returns>
|
||||
Task<byte[]> DownloadFileAsync(int fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a list of files from a <see cref="Site"/> and <see cref="Folder"/>
|
||||
/// </summary>
|
||||
/// <param name="siteId">Reference to the <see cref="Site"/></param>
|
||||
/// <param name="folderPath">Path of the folder
|
||||
/// TODO: todoc verify exactly from where the folder path must start
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task<List<File>> GetFilesAsync(int siteId, string folderPath);
|
||||
|
||||
/// <summary>
|
||||
/// Unzips the contents of a zip file
|
||||
/// </summary>
|
||||
/// <param name="fileId">Reference to the <see cref="File"/></param>
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task UnzipFileAsync(int fileId);
|
||||
}
|
||||
}
|
59
Oqtane.Client/Services/Interfaces/IFolderService.cs
Normal file
59
Oqtane.Client/Services/Interfaces/IFolderService.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to get / create / modify <see cref="Folder"/> objects.
|
||||
/// </summary>
|
||||
public interface IFolderService
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve root folders of a <see cref="Site"/>
|
||||
/// </summary>
|
||||
/// <param name="siteId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<Folder>> GetFoldersAsync(int siteId);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the information of one <see cref="Folder"/>
|
||||
/// </summary>
|
||||
/// <param name="folderId"></param>
|
||||
/// <returns></returns>
|
||||
Task<Folder> GetFolderAsync(int folderId);
|
||||
|
||||
/// <summary>
|
||||
/// Create one Folder using a <see cref="Folder"/> object.
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
/// <returns></returns>
|
||||
Task<Folder> AddFolderAsync(Folder folder);
|
||||
|
||||
/// <summary>
|
||||
/// Update the information about a <see cref="Folder"/>
|
||||
/// Use this to rename the folder etc.
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
/// <returns></returns>
|
||||
Task<Folder> UpdateFolderAsync(Folder folder);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a <see cref="Folder"/>
|
||||
/// </summary>
|
||||
/// <param name="folderId">Reference to a <see cref="Folder"/></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteFolderAsync(int folderId);
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="Folder"/> of a <see cref="Site"/> based on the path.
|
||||
/// </summary>
|
||||
/// <param name="siteId">Reference to the <see cref="Site"/></param>
|
||||
/// <param name="folderPath">Path of the folder
|
||||
/// TODO: todoc verify exactly from where the folder path must start
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
Task<Folder> GetFolderAsync(int siteId, [NotNull]string folderPath);
|
||||
}
|
||||
}
|
39
Oqtane.Client/Services/Interfaces/IInstallationService.cs
Normal file
39
Oqtane.Client/Services/Interfaces/IInstallationService.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using Oqtane.Models;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Service to manage (install master database / upgrade version / etc.) the installation
|
||||
/// </summary>
|
||||
public interface IInstallationService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a status/message object with the current installation state
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<Installation> IsInstalled();
|
||||
|
||||
/// <summary>
|
||||
/// Starts the installation process
|
||||
/// </summary>
|
||||
/// <param name="config">connectionString, database type, alias etc.</param>
|
||||
/// <returns>internal status/message object</returns>
|
||||
Task<Installation> Install(InstallConfig config);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the upgrade process
|
||||
/// </summary>
|
||||
/// <param name="backup">indicates if files should be backed up during upgrade</param>
|
||||
/// <returns>internal status/message object</returns>
|
||||
Task<Installation> Upgrade(bool backup);
|
||||
|
||||
/// <summary>
|
||||
/// Restarts the installation
|
||||
/// </summary>
|
||||
/// <returns>internal status/message object</returns>
|
||||
Task RestartAsync();
|
||||
}
|
||||
}
|
26
Oqtane.Client/Services/Interfaces/IJobLogService.cs
Normal file
26
Oqtane.Client/Services/Interfaces/IJobLogService.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to read the job schedule log
|
||||
/// </summary>
|
||||
public interface IJobLogService
|
||||
{
|
||||
/// <summary>
|
||||
/// Return a list of <see cref="JobLog"/> entries
|
||||
/// </summary>
|
||||
/// <param name="jobId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<JobLog>> GetJobLogsAsync(int jobId);
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="JobLog"/> entry for the given Id
|
||||
/// </summary>
|
||||
/// <param name="jobLogId"></param>
|
||||
/// <returns></returns>
|
||||
Task<JobLog> GetJobLogAsync(int jobLogId);
|
||||
}
|
||||
}
|
61
Oqtane.Client/Services/Interfaces/IJobService.cs
Normal file
61
Oqtane.Client/Services/Interfaces/IJobService.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Service to manage jobs (<see cref="Job"/>)
|
||||
/// </summary>
|
||||
public interface IJobService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a list of all jobs
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<Job>> GetJobsAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Return a specific job
|
||||
/// </summary>
|
||||
/// <param name="jobId"></param>
|
||||
/// <returns></returns>
|
||||
Task<Job> GetJobAsync(int jobId);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new job
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
/// <returns></returns>
|
||||
Task<Job> AddJobAsync(Job job);
|
||||
|
||||
/// <summary>
|
||||
/// Updates an existing job
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
/// <returns></returns>
|
||||
Task<Job> UpdateJobAsync(Job job);
|
||||
|
||||
/// <summary>
|
||||
/// Delete an existing job
|
||||
/// </summary>
|
||||
/// <param name="jobId"></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteJobAsync(int jobId);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the given job
|
||||
/// </summary>
|
||||
/// <param name="jobId"></param>
|
||||
/// <returns></returns>
|
||||
Task StartJobAsync(int jobId);
|
||||
|
||||
/// <summary>
|
||||
/// Stops the given job
|
||||
/// </summary>
|
||||
/// <param name="jobId"></param>
|
||||
/// <returns></returns>
|
||||
Task StopJobAsync(int jobId);
|
||||
}
|
||||
}
|
56
Oqtane.Client/Services/Interfaces/ILanguageService.cs
Normal file
56
Oqtane.Client/Services/Interfaces/ILanguageService.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Service to manage <see cref="Language"/> entries
|
||||
/// </summary>
|
||||
public interface ILanguageService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a list of all available languages for the given <see cref="Site"/>
|
||||
/// </summary>
|
||||
/// <param name="siteId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<Language>> GetLanguagesAsync(int siteId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all available languages for the given <see cref="Site" /> and package
|
||||
/// </summary>
|
||||
/// <param name="siteId"></param>
|
||||
/// <param name="packageName"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<Language>> GetLanguagesAsync(int siteId, string packageName);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the given language
|
||||
/// </summary>
|
||||
/// <param name="languageId"></param>
|
||||
/// <returns></returns>
|
||||
Task<Language> GetLanguageAsync(int languageId);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given language
|
||||
/// </summary>
|
||||
/// <param name="language"></param>
|
||||
/// <returns></returns>
|
||||
Task<Language> AddLanguageAsync(Language language);
|
||||
|
||||
/// <summary>
|
||||
/// Edits the given language
|
||||
/// </summary>
|
||||
/// <param name="language"></param>
|
||||
/// <returns></returns>
|
||||
Task EditLanguageAsync(Language language);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the given language
|
||||
/// </summary>
|
||||
/// <param name="languageId"></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteLanguageAsync(int languageId);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user