Compare commits
333 Commits
Author | SHA1 | Date | |
---|---|---|---|
3259494d45 | |||
0a03eb620a | |||
701d8c9a57 | |||
fdca8a2890 | |||
22e2a4da1e | |||
409523912b | |||
d5c68444c3 | |||
ffa93e0ee7 | |||
3f4f1a8278 | |||
8e70949880 | |||
be8436d237 | |||
876f13be5e | |||
dfca6640da | |||
a2e57bc54c | |||
dcc2e59e46 | |||
90e721b172 | |||
94391875d5 | |||
43d06c042d | |||
3e12910fbd | |||
ba70ebe23c | |||
b739841495 | |||
acabc75aa6 | |||
27041f464f | |||
9f923ae968 | |||
9c7d832357 | |||
e913c10d5b | |||
c698188901 | |||
8fd67621ac | |||
0c60085e09 | |||
1826316c80 | |||
07341aeebe | |||
9f6945dda2 | |||
b39b568b4c | |||
e59d5fd339 | |||
b7bc527d6c | |||
1ea76d06d1 | |||
b049be9d83 | |||
966fc55594 | |||
ca9ddbd90f | |||
0d04926d9f | |||
2b500d41ca | |||
5c67eeea58 | |||
09daf3f6cc | |||
9a06a3311e | |||
304694fbf9 | |||
96ba42df96 | |||
e7bc11d026 | |||
1272305355 | |||
30c6da13c2 | |||
5aacb2b877 | |||
b5fdf42c37 | |||
c81d677c5c | |||
6daf675e52 | |||
3f7a7f3340 | |||
1ebf3c4077 | |||
1f1173ae03 | |||
efa466e1d6 | |||
cefe349b4e | |||
a9bc356f37 | |||
6fc791020c | |||
713ec1b373 | |||
e3fa781122 | |||
e4b6d0ff29 | |||
cd2a328560 | |||
d2d88d4b5e | |||
0067cc4266 | |||
da3afefa8d | |||
ab534d07f3 | |||
49c513ac9b | |||
6f7a18674e | |||
0f559ba42d | |||
2af02fae95 | |||
006423e32e | |||
23f29ca55d | |||
68a7571741 | |||
10e60e352a | |||
3b16ae8cc0 | |||
66c4737021 | |||
8684e03af1 | |||
edad9e6b3c | |||
66b89752d3 | |||
9a6195edf1 | |||
2bd07b54b6 | |||
7cf9d9ad65 | |||
4dff30ec8c | |||
581f14e661 | |||
8ccdc37b64 | |||
9e85b35498 | |||
fff408a5bf | |||
4d5168c998 | |||
bf2c978f1d | |||
ec06c1cdf1 | |||
f451cfce09 | |||
91e55aeb9b | |||
919fb5012f | |||
2bb6226e78 | |||
6a0c47f7b1 | |||
31b688cbf6 | |||
7f1fed2fb1 | |||
aa6c876b12 | |||
4e33aeef89 | |||
e2601dcf05 | |||
247baa375d | |||
a4adba846e | |||
52799c7cb0 | |||
a8635dc555 | |||
cca0f2219e | |||
d2f8c3c2bb | |||
0f38df053f | |||
5c926a10a7 | |||
036bbb418e | |||
93d224fa37 | |||
5b45e3e417 | |||
c2f2dfd837 | |||
2f2baf12fb | |||
052c339d0d | |||
96192e2e06 | |||
ea9fa30358 | |||
78f8e2f484 | |||
0fe2a3fb80 | |||
a340f52973 | |||
bd94b715ba | |||
b9a97ffa4c | |||
5a37ab1b89 | |||
67a6ac2240 | |||
7b42845ecc | |||
3ef39896d1 | |||
b01f3b505d | |||
84c5e4c30b | |||
abc0f3943e | |||
c7b71db015 | |||
f5a8a953bb | |||
8e965912aa | |||
6c3cfb0c7a | |||
85d162aa9d | |||
67c460dfa5 | |||
83d35dbc65 | |||
86735a5afd | |||
6ecbb89469 | |||
2ca0508030 | |||
8fbd50dcef | |||
2143660345 | |||
8c903fbfdd | |||
33be372348 | |||
447ec3f5e6 | |||
a4aed69887 | |||
bbbd6e9e3e | |||
06712faee9 | |||
48a90072ee | |||
0344f4d60b | |||
6a4affd5a6 | |||
d73e2288bb | |||
7d7500ba05 | |||
247fc5248b | |||
85fcd1ed33 | |||
4ab8f8cc25 | |||
ccdfe9bc26 | |||
dc47961cc2 | |||
87394cd330 | |||
b5a9c32c3e | |||
d16521f037 | |||
b553b16049 | |||
784548be57 | |||
cf96a80ead | |||
ede6babeaf | |||
9a57cae4bd | |||
1a296bf58c | |||
e900d2f35a | |||
69d2d3d942 | |||
b7ff49bdb2 | |||
3284e0f60a | |||
8cec847188 | |||
2d44644a3d | |||
e32f55e433 | |||
362c4ae272 | |||
eb8ad04557 | |||
d1455596c6 | |||
6142bfc5db | |||
dbda0be53b | |||
bf932719b2 | |||
60e6e33805 | |||
64b8b5d3c8 | |||
8bce40c2b8 | |||
b3f6194fda | |||
fdbf2ab0a7 | |||
d7eb0dc509 | |||
1a34bf4460 | |||
4cf1b5c0e7 | |||
764b883579 | |||
3bd6767138 | |||
bef9025b6c | |||
a37f07d20b | |||
638946b1f5 | |||
30c869ff2a | |||
2c3fda9cb5 | |||
b11a7a678c | |||
02011f9ce5 | |||
39ae6a76cd | |||
31684bf7ca | |||
7b36f8d122 | |||
f2a0be4f57 | |||
2cefab1c64 | |||
5b4b96f065 | |||
77949331e2 | |||
4f8c4f47e2 | |||
334137454e | |||
af7ea3efa8 | |||
6119417331 | |||
580397a82d | |||
23c3c47db4 | |||
df3073fb12 | |||
aa9664e187 | |||
44f4aee55d | |||
02861b8e01 | |||
9607110381 | |||
9ae12ff678 | |||
2bcb8636ca | |||
4c2960eeae | |||
7e2c76e872 | |||
30fcde7157 | |||
4971d3317d | |||
85ae7b01b8 | |||
9f566624fe | |||
50fa95dff9 | |||
752083e9eb | |||
582c7f83f7 | |||
d95104cb92 | |||
6c58ab4554 | |||
085187cfac | |||
3d0f0a5adc | |||
eae8b431ee | |||
e3a34446c0 | |||
bfe57c3ac7 | |||
d4001be716 | |||
662a1817f2 | |||
2c99ef412d | |||
f53ed5b13b | |||
b5d51838c6 | |||
92fd70198a | |||
7f1990f851 | |||
797d7afc3e | |||
c5a23cdfa0 | |||
906358f1f8 | |||
638f2a59c5 | |||
cf9b4b869c | |||
671c52fbbb | |||
6c0e2a62e7 | |||
1b78c9ad81 | |||
7a4b98aec9 | |||
9ef6c15014 | |||
f4cea3fe03 | |||
5dd9b1ec91 | |||
658059806b | |||
4f8a18451c | |||
b1770ebb76 | |||
6923065d86 | |||
9f097521f6 | |||
235e5c1d3a | |||
e179976fe8 | |||
082726b405 | |||
91c5309855 | |||
92be1e7a5c | |||
cceda1db1e | |||
a59191cea7 | |||
b0dee4a60c | |||
3f33f2b9df | |||
97116b4e0c | |||
a5f51ff9a1 | |||
962488fd34 | |||
190d973b77 | |||
397e0b3f71 | |||
83ba9ca73e | |||
3d08138686 | |||
262fa6b99b | |||
372db9dcfa | |||
e9dc52919c | |||
a981dd0e97 | |||
7c2775119b | |||
0be7f1bdb5 | |||
8446b9e8d5 | |||
ce404668d3 | |||
948fab50ee | |||
9690f1df48 | |||
5a24f87293 | |||
d2ff49fe73 | |||
e9035df9d2 | |||
1ddf21f4fc | |||
63d2ded038 | |||
7b8e0e48c0 | |||
bb52402a17 | |||
13d9cb461b | |||
0a994afd67 | |||
57a1257750 | |||
b0c1d36bab | |||
0621751968 | |||
461330773a | |||
818a97cc2c | |||
17045073c8 | |||
7a818ee698 | |||
668e0cb4eb | |||
741b16ca4e | |||
85a376b17d | |||
df86cd909c | |||
ac236607f5 | |||
19813b7eb6 | |||
cb5e4e076f | |||
48fca77f59 | |||
76372451aa | |||
34cd197122 | |||
6b567364f9 | |||
711de49571 | |||
9a0f7ad83f | |||
0d3d693799 | |||
b63590d6c7 | |||
5f3a3d4d54 | |||
b1a8c28283 | |||
1412737036 | |||
ffb3f4fa50 | |||
ff450ca43a | |||
d4f0805108 | |||
64ce69d1c7 | |||
ca3cb48091 | |||
85085bf4c7 | |||
873af6b598 | |||
c423895f31 | |||
4418e27c29 | |||
f776977af8 | |||
c13ce3d0f1 | |||
2c4c669ea2 | |||
018737c42a | |||
3811b8f0c0 | |||
d81514e9be | |||
14b0d7abf0 |
@ -1,25 +0,0 @@
|
||||
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
@ -1,24 +0,0 @@
|
||||
# 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
Normal file
@ -0,0 +1,9 @@
|
||||
.vs/
|
||||
bin/
|
||||
obj/
|
||||
*.user
|
||||
artifacts/
|
||||
msbuild.binlog
|
||||
.vscode/
|
||||
*.binlog
|
||||
*.nupkg
|
19
Oqtane.Application/.template.config/template.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"$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
|
||||
}
|
3
Oqtane.Application/Client/AssemblyInfo.cs
Normal file
@ -0,0 +1,3 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
[assembly: RootNamespace("Oqtane.Application.Client")]
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.JSInterop;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace [Owner].Module.[Module]
|
||||
namespace Oqtane.Application
|
||||
{
|
||||
public class Interop
|
||||
{
|
@ -1,10 +1,10 @@
|
||||
@using Oqtane.Modules.Controls
|
||||
@using [Owner].Module.[Module].Services
|
||||
@using [Owner].Module.[Module].Models
|
||||
@using Oqtane.Application.Services
|
||||
@using Oqtane.Application.Models
|
||||
|
||||
@namespace [Owner].Module.[Module]
|
||||
@namespace Oqtane.Application.MyModule
|
||||
@inherits ModuleBase
|
||||
@inject I[Module]Service [Module]Service
|
||||
@inject IMyModuleService MyModuleService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
|
||||
@ -31,11 +31,11 @@
|
||||
|
||||
public override string Actions => "Add,Edit";
|
||||
|
||||
public override string Title => "Manage [Module]";
|
||||
public override string Title => "Manage MyModule";
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
||||
new Stylesheet(ModulePath() + "Module.css")
|
||||
};
|
||||
|
||||
private ElementReference form;
|
||||
@ -55,20 +55,20 @@
|
||||
if (PageState.Action == "Edit")
|
||||
{
|
||||
_id = Int32.Parse(PageState.QueryString["id"]);
|
||||
[Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
||||
if ([Module] != null)
|
||||
MyModule MyModule = await MyModuleService.GetMyModuleAsync(_id, ModuleState.ModuleId);
|
||||
if (MyModule != null)
|
||||
{
|
||||
_name = [Module].Name;
|
||||
_createdby = [Module].CreatedBy;
|
||||
_createdon = [Module].CreatedOn;
|
||||
_modifiedby = [Module].ModifiedBy;
|
||||
_modifiedon = [Module].ModifiedOn;
|
||||
_name = MyModule.Name;
|
||||
_createdby = MyModule.CreatedBy;
|
||||
_createdon = MyModule.CreatedOn;
|
||||
_modifiedby = MyModule.ModifiedBy;
|
||||
_modifiedon = MyModule.ModifiedOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading [Module] {[Module]Id} {Error}", _id, ex.Message);
|
||||
await logger.LogError(ex, "Error Loading MyModule {MyModuleId} {Error}", _id, ex.Message);
|
||||
AddModuleMessage(Localizer["Message.LoadError"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
@ -83,18 +83,18 @@
|
||||
{
|
||||
if (PageState.Action == "Add")
|
||||
{
|
||||
[Module] [Module] = new [Module]();
|
||||
[Module].ModuleId = ModuleState.ModuleId;
|
||||
[Module].Name = _name;
|
||||
[Module] = await [Module]Service.Add[Module]Async([Module]);
|
||||
await logger.LogInformation("[Module] Added {[Module]}", [Module]);
|
||||
MyModule MyModule = new MyModule();
|
||||
MyModule.ModuleId = ModuleState.ModuleId;
|
||||
MyModule.Name = _name;
|
||||
MyModule = await MyModuleService.AddMyModuleAsync(MyModule);
|
||||
await logger.LogInformation("MyModule Added {MyModule}", MyModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
[Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
||||
[Module].Name = _name;
|
||||
await [Module]Service.Update[Module]Async([Module]);
|
||||
await logger.LogInformation("[Module] Updated {[Module]}", [Module]);
|
||||
MyModule MyModule = await MyModuleService.GetMyModuleAsync(_id, ModuleState.ModuleId);
|
||||
MyModule.Name = _name;
|
||||
await MyModuleService.UpdateMyModuleAsync(MyModule);
|
||||
await logger.LogInformation("MyModule Updated {MyModule}", MyModule);
|
||||
}
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
@ -105,7 +105,7 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving [Module] {Error}", ex.Message);
|
||||
await logger.LogError(ex, "Error Saving MyModule {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Message.SaveError"], MessageType.Error);
|
||||
}
|
||||
}
|
@ -1,32 +1,32 @@
|
||||
@using [Owner].Module.[Module].Services
|
||||
@using [Owner].Module.[Module].Models
|
||||
@using Oqtane.Application.Services
|
||||
@using Oqtane.Application.Models
|
||||
|
||||
@namespace [Owner].Module.[Module]
|
||||
@namespace Oqtane.Application.MyModule
|
||||
@inherits ModuleBase
|
||||
@inject I[Module]Service [Module]Service
|
||||
@inject IMyModuleService MyModuleService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
|
||||
@if (_[Module]s == null)
|
||||
@if (_MyModules == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ActionLink Action="Add" Security="SecurityAccessLevel.Edit" Text="Add [Module]" ResourceKey="Add" />
|
||||
<ActionLink Action="Add" Security="SecurityAccessLevel.Edit" Text="Add MyModule" ResourceKey="Add" />
|
||||
<br />
|
||||
<br />
|
||||
@if (@_[Module]s.Count != 0)
|
||||
@if (@_MyModules.Count != 0)
|
||||
{
|
||||
<Pager Items="@_[Module]s">
|
||||
<Pager Items="@_MyModules">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Name"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.[Module]Id.ToString())" ResourceKey="Edit" /></td>
|
||||
<td><ActionDialog Header="Delete [Module]" Message="Are You Sure You Wish To Delete This [Module]?" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" ResourceKey="Delete" Id="@context.[Module]Id.ToString()" /></td>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.MyModuleId.ToString())" ResourceKey="Edit" /></td>
|
||||
<td><ActionDialog Header="Delete MyModule" Message="Are You Sure You Wish To Delete This MyModule?" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" ResourceKey="Delete" Id="@context.MyModuleId.ToString()" /></td>
|
||||
<td>@context.Name</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
@ -38,41 +38,39 @@ else
|
||||
}
|
||||
|
||||
@code {
|
||||
public override string RenderMode => RenderModes.Static;
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
|
||||
new Resource { ResourceType = ResourceType.Script, Url = ModulePath() + "Module.js" }
|
||||
new Stylesheet(ModulePath() + "Module.css"),
|
||||
new Script(ModulePath() + "Module.js")
|
||||
};
|
||||
|
||||
List<[Module]> _[Module]s;
|
||||
List<Models.MyModule> _MyModules;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
||||
_MyModules = await MyModuleService.GetMyModulesAsync(ModuleState.ModuleId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading [Module] {Error}", ex.Message);
|
||||
await logger.LogError(ex, "Error Loading MyModule {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Message.LoadError"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Delete([Module] [Module])
|
||||
private async Task Delete(MyModule MyModule)
|
||||
{
|
||||
try
|
||||
{
|
||||
await [Module]Service.Delete[Module]Async([Module].[Module]Id, ModuleState.ModuleId);
|
||||
await logger.LogInformation("[Module] Deleted {[Module]}", [Module]);
|
||||
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
||||
await MyModuleService.DeleteMyModuleAsync(MyModule.MyModuleId, ModuleState.ModuleId);
|
||||
await logger.LogInformation("MyModule Deleted {MyModule}", MyModule);
|
||||
_MyModules = await MyModuleService.GetMyModulesAsync(ModuleState.ModuleId);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting [Module] {[Module]} {Error}", [Module], ex.Message);
|
||||
await logger.LogError(ex, "Error Deleting MyModule {MyModule} {Error}", MyModule, ex.Message);
|
||||
AddModuleMessage(Localizer["Message.DeleteError"], MessageType.Error);
|
||||
}
|
||||
}
|
19
Oqtane.Application/Client/Modules/MyModule/ModuleInfo.cs
Normal file
@ -0,0 +1,19 @@
|
||||
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,4 +1,4 @@
|
||||
@namespace [Owner].Module.[Module]
|
||||
@namespace Oqtane.Application.MyModule
|
||||
@inherits ModuleBase
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Settings> Localizer
|
||||
@ -13,8 +13,8 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string resourceType = "[Owner].Module.[Module].Settings, [Owner].Module.[Module].Client.Oqtane"; // for localization
|
||||
public override string Title => "[Module] Settings";
|
||||
private string resourceType = "Oqtane.Application.Settings, Oqtane.Application.Client.Oqtane"; // for localization
|
||||
public override string Title => "MyModdule Settings";
|
||||
|
||||
string _value;
|
||||
|
21
Oqtane.Application/Client/Oqtane.Application.Client.csproj
Normal file
@ -0,0 +1,21 @@
|
||||
<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>
|
13
Oqtane.Application/Client/Program.cs
Normal file
@ -0,0 +1,13 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
<?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>
|
@ -0,0 +1,147 @@
|
||||
<?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,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
55
Oqtane.Application/Client/Services/MyModuleService.cs
Normal file
@ -0,0 +1,55 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
18
Oqtane.Application/Client/Startup/ClientStartup.cs
Normal file
@ -0,0 +1,18 @@
|
||||
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,4 +1,4 @@
|
||||
@namespace [Owner].Theme.[Theme]
|
||||
@namespace Oqtane.Application.MyTheme
|
||||
@inherits ContainerBase
|
||||
@inject ISettingService SettingService
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
public override string Name => "[Owner] [Theme] - Container1";
|
||||
public override string Name => "Container";
|
||||
|
||||
private bool _title = true;
|
||||
private string _classes = "container-fluid";
|
@ -1,4 +1,4 @@
|
||||
@namespace [Owner].Theme.[Theme]
|
||||
@namespace Oqtane.Application.MyTheme
|
||||
@inherits ModuleBase
|
||||
@implements Oqtane.Interfaces.ISettingsControl
|
||||
@inject ISettingService SettingService
|
||||
@ -17,7 +17,7 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string resourceType = "[Owner].Theme.[Theme].ContainerSettings, [Owner].Theme.[Theme].Client.Oqtane"; // for localization
|
||||
private string resourceType = "Oqtane.Application.MyTheme.ContainerSettings, Oqtane.Application.Client.Oqtane"; // for localization
|
||||
private string _title = "true";
|
||||
|
||||
protected override void OnInitialized()
|
25
Oqtane.Application/Client/Themes/MyTheme/ThemeInfo.cs
Normal file
@ -0,0 +1,25 @@
|
||||
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,4 +1,4 @@
|
||||
@namespace [Owner].Theme.[Theme]
|
||||
@namespace Oqtane.Application.MyTheme
|
||||
@inherits ThemeBase
|
||||
@inject ISettingService SettingService
|
||||
|
||||
@ -95,7 +95,7 @@
|
||||
</main>
|
||||
|
||||
@code {
|
||||
public override string Name => "Theme1";
|
||||
public override string Name => "MyTheme";
|
||||
|
||||
public override string Panes => PaneNames.Admin + ",Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width";
|
||||
|
@ -1,4 +1,4 @@
|
||||
@namespace [Owner].Theme.[Theme]
|
||||
@namespace Oqtane.Application.MyTheme
|
||||
@inherits ModuleBase
|
||||
@implements Oqtane.Interfaces.ISettingsControl
|
||||
@inject ISettingService SettingService
|
||||
@ -43,7 +43,7 @@
|
||||
|
||||
@code {
|
||||
private int pageId = -1;
|
||||
private string resourceType = "[Owner].Theme.[Theme].ThemeSettings, [Owner].Theme.[Theme].Client.Oqtane"; // for localization
|
||||
private string resourceType = "Oqtane.Application.MyTheme.ThemeSettings, Oqtane.Application.Client.Oqtane"; // for localization
|
||||
private string _scope = "page";
|
||||
private string _login = "-";
|
||||
private string _register = "-";
|
@ -1,4 +1,4 @@
|
||||
@using System
|
||||
@using System
|
||||
@using System.Linq
|
||||
@using System.Collections.Generic
|
||||
@using System.Net.Http
|
||||
@ -10,6 +10,7 @@
|
||||
@using Microsoft.Extensions.Localization
|
||||
@using Microsoft.JSInterop
|
||||
|
||||
@using Oqtane
|
||||
@using Oqtane.Models
|
||||
@using Oqtane.Modules
|
||||
@using Oqtane.Modules.Controls
|
21
Oqtane.Application/Oqtane.Application.Template.nuspec
Normal file
@ -0,0 +1,21 @@
|
||||
<?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>
|
33
Oqtane.Application/Oqtane.Application.sln
Normal file
@ -0,0 +1,33 @@
|
||||
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
|
19
Oqtane.Application/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
# 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
|
||||
|
3
Oqtane.Application/Server/AssemblyInfo.cs
Normal file
@ -0,0 +1,3 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
[assembly: RootNamespace("Oqtane.Application.Server")]
|
@ -5,36 +5,36 @@ using Microsoft.AspNetCore.Http;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Infrastructure;
|
||||
using [Owner].Module.[Module].Services;
|
||||
using Oqtane.Application.Services;
|
||||
using Oqtane.Controllers;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace [Owner].Module.[Module].Controllers
|
||||
namespace Oqtane.Application.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class [Module]Controller : ModuleControllerBase
|
||||
public class MyModuleController : ModuleControllerBase
|
||||
{
|
||||
private readonly I[Module]Service _[Module]Service;
|
||||
private readonly IMyModuleService _MyModuleService;
|
||||
|
||||
public [Module]Controller(I[Module]Service [Module]Service, ILogManager logger, IHttpContextAccessor accessor) : base(logger, accessor)
|
||||
public MyModuleController(IMyModuleService MyModuleService, ILogManager logger, IHttpContextAccessor accessor) : base(logger, accessor)
|
||||
{
|
||||
_[Module]Service = [Module]Service;
|
||||
_MyModuleService = MyModuleService;
|
||||
}
|
||||
|
||||
// GET: api/<controller>?moduleid=x
|
||||
[HttpGet]
|
||||
[Authorize(Policy = PolicyNames.ViewModule)]
|
||||
public async Task<IEnumerable<Models.[Module]>> Get(string moduleid)
|
||||
public async Task<IEnumerable<Models.MyModule>> Get(string moduleid)
|
||||
{
|
||||
int ModuleId;
|
||||
if (int.TryParse(moduleid, out ModuleId) && IsAuthorizedEntityId(EntityNames.Module, ModuleId))
|
||||
{
|
||||
return await _[Module]Service.Get[Module]sAsync(ModuleId);
|
||||
return await _MyModuleService.GetMyModulesAsync(ModuleId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Get Attempt {ModuleId}", moduleid);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized MyModule Get Attempt {ModuleId}", moduleid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
@ -43,16 +43,16 @@ namespace [Owner].Module.[Module].Controllers
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}/{moduleid}")]
|
||||
[Authorize(Policy = PolicyNames.ViewModule)]
|
||||
public async Task<Models.[Module]> Get(int id, int moduleid)
|
||||
public async Task<Models.MyModule> Get(int id, int moduleid)
|
||||
{
|
||||
Models.[Module] [Module] = await _[Module]Service.Get[Module]Async(id, moduleid);
|
||||
if ([Module] != null && IsAuthorizedEntityId(EntityNames.Module, [Module].ModuleId))
|
||||
Models.MyModule MyModule = await _MyModuleService.GetMyModuleAsync(id, moduleid);
|
||||
if (MyModule != null && IsAuthorizedEntityId(EntityNames.Module, MyModule.ModuleId))
|
||||
{
|
||||
return [Module];
|
||||
return MyModule;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Get Attempt {[Module]Id} {ModuleId}", id, moduleid);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized MyModule Get Attempt {MyModuleId} {ModuleId}", id, moduleid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
@ -61,37 +61,37 @@ namespace [Owner].Module.[Module].Controllers
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Policy = PolicyNames.EditModule)]
|
||||
public async Task<Models.[Module]> Post([FromBody] Models.[Module] [Module])
|
||||
public async Task<Models.MyModule> Post([FromBody] Models.MyModule MyModule)
|
||||
{
|
||||
if (ModelState.IsValid && IsAuthorizedEntityId(EntityNames.Module, [Module].ModuleId))
|
||||
if (ModelState.IsValid && IsAuthorizedEntityId(EntityNames.Module, MyModule.ModuleId))
|
||||
{
|
||||
[Module] = await _[Module]Service.Add[Module]Async([Module]);
|
||||
MyModule = await _MyModuleService.AddMyModuleAsync(MyModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Post Attempt {[Module]}", [Module]);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized MyModule Post Attempt {MyModule}", MyModule);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
[Module] = null;
|
||||
MyModule = null;
|
||||
}
|
||||
return [Module];
|
||||
return MyModule;
|
||||
}
|
||||
|
||||
// PUT api/<controller>/5
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Policy = PolicyNames.EditModule)]
|
||||
public async Task<Models.[Module]> Put(int id, [FromBody] Models.[Module] [Module])
|
||||
public async Task<Models.MyModule> Put(int id, [FromBody] Models.MyModule MyModule)
|
||||
{
|
||||
if (ModelState.IsValid && [Module].[Module]Id == id && IsAuthorizedEntityId(EntityNames.Module, [Module].ModuleId))
|
||||
if (ModelState.IsValid && MyModule.MyModuleId == id && IsAuthorizedEntityId(EntityNames.Module, MyModule.ModuleId))
|
||||
{
|
||||
[Module] = await _[Module]Service.Update[Module]Async([Module]);
|
||||
MyModule = await _MyModuleService.UpdateMyModuleAsync(MyModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Put Attempt {[Module]}", [Module]);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized MyModule Put Attempt {MyModule}", MyModule);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
[Module] = null;
|
||||
MyModule = null;
|
||||
}
|
||||
return [Module];
|
||||
return MyModule;
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/5
|
||||
@ -99,14 +99,14 @@ namespace [Owner].Module.[Module].Controllers
|
||||
[Authorize(Policy = PolicyNames.EditModule)]
|
||||
public async Task Delete(int id, int moduleid)
|
||||
{
|
||||
Models.[Module] [Module] = await _[Module]Service.Get[Module]Async(id, moduleid);
|
||||
if ([Module] != null && IsAuthorizedEntityId(EntityNames.Module, [Module].ModuleId))
|
||||
Models.MyModule MyModule = await _MyModuleService.GetMyModuleAsync(id, moduleid);
|
||||
if (MyModule != null && IsAuthorizedEntityId(EntityNames.Module, MyModule.ModuleId))
|
||||
{
|
||||
await _[Module]Service.Delete[Module]Async(id, [Module].ModuleId);
|
||||
await _MyModuleService.DeleteMyModuleAsync(id, MyModule.ModuleId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Delete Attempt {[Module]Id} {ModuleId}", id, moduleid);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized v Delete Attempt {MyModuleId} {ModuleId}", id, moduleid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
87
Oqtane.Application/Server/Manager/MyModuleManager.cs
Normal file
@ -0,0 +1,87 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,13 +2,13 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations;
|
||||
using [Owner].Module.[Module].Migrations.EntityBuilders;
|
||||
using [Owner].Module.[Module].Repository;
|
||||
using Oqtane.Application.Migrations.EntityBuilders;
|
||||
using Oqtane.Application.Repository;
|
||||
|
||||
namespace [Owner].Module.[Module].Migrations
|
||||
namespace Oqtane.Application.Migrations
|
||||
{
|
||||
[DbContext(typeof([Module]Context))]
|
||||
[Migration("[Owner].Module.[Module].01.00.00.00")]
|
||||
[DbContext(typeof(Context))]
|
||||
[Migration("Oqtane.Application.01.00.00.00")]
|
||||
public class InitializeModule : MultiDatabaseMigration
|
||||
{
|
||||
public InitializeModule(IDatabase database) : base(database)
|
||||
@ -17,14 +17,14 @@ namespace [Owner].Module.[Module].Migrations
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
var entityBuilder = new [Module]EntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
entityBuilder.Create();
|
||||
var myModuleEntityBuilder = new MyModuleEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
myModuleEntityBuilder.Create();
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
var entityBuilder = new [Module]EntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
entityBuilder.Drop();
|
||||
var myModuleEntityBuilder = new MyModuleEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
myModuleEntityBuilder.Drop();
|
||||
}
|
||||
}
|
||||
}
|
@ -5,31 +5,31 @@ using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
|
||||
namespace [Owner].Module.[Module].Migrations.EntityBuilders
|
||||
namespace Oqtane.Application.Migrations.EntityBuilders
|
||||
{
|
||||
public class [Module]EntityBuilder : AuditableBaseEntityBuilder<[Module]EntityBuilder>
|
||||
public class MyModuleEntityBuilder : AuditableBaseEntityBuilder<MyModuleEntityBuilder>
|
||||
{
|
||||
private const string _entityTableName = "[Owner][Module]";
|
||||
private readonly PrimaryKey<[Module]EntityBuilder> _primaryKey = new("PK_[Owner][Module]", x => x.[Module]Id);
|
||||
private readonly ForeignKey<[Module]EntityBuilder> _moduleForeignKey = new("FK_[Owner][Module]_Module", x => x.ModuleId, "Module", "ModuleId", ReferentialAction.Cascade);
|
||||
private const string _entityTableName = "MyModule";
|
||||
private readonly PrimaryKey<MyModuleEntityBuilder> _primaryKey = new("PK_MyModule", x => x.MyModuleId);
|
||||
private readonly ForeignKey<MyModuleEntityBuilder> _moduleForeignKey = new("FK_MyModule_Module", x => x.ModuleId, "Module", "ModuleId", ReferentialAction.Cascade);
|
||||
|
||||
public [Module]EntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
public MyModuleEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
ForeignKeys.Add(_moduleForeignKey);
|
||||
}
|
||||
|
||||
protected override [Module]EntityBuilder BuildTable(ColumnsBuilder table)
|
||||
protected override MyModuleEntityBuilder BuildTable(ColumnsBuilder table)
|
||||
{
|
||||
[Module]Id = AddAutoIncrementColumn(table,"[Module]Id");
|
||||
MyModuleId = AddAutoIncrementColumn(table, "MyModuleId");
|
||||
ModuleId = AddIntegerColumn(table,"ModuleId");
|
||||
Name = AddMaxStringColumn(table,"Name");
|
||||
AddAuditableColumns(table);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OperationBuilder<AddColumnOperation> [Module]Id { get; set; }
|
||||
public OperationBuilder<AddColumnOperation> MyModuleId { get; set; }
|
||||
public OperationBuilder<AddColumnOperation> ModuleId { get; set; }
|
||||
public OperationBuilder<AddColumnOperation> Name { get; set; }
|
||||
}
|
18
Oqtane.Application/Server/Oqtane.Application.Server.csproj
Normal file
@ -0,0 +1,18 @@
|
||||
<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>
|
42
Oqtane.Application/Server/Program.cs
Normal file
@ -0,0 +1,42 @@
|
||||
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();
|
||||
}
|
||||
}
|
25
Oqtane.Application/Server/Properties/launchSettings.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"$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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
Oqtane.Application/Server/Repository/Context.cs
Normal file
@ -0,0 +1,24 @@
|
||||
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"));
|
||||
}
|
||||
}
|
||||
}
|
75
Oqtane.Application/Server/Repository/MyModuleRepository.cs
Normal file
@ -0,0 +1,75 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@ -7,93 +7,93 @@ using Oqtane.Infrastructure;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Security;
|
||||
using Oqtane.Shared;
|
||||
using [Owner].Module.[Module].Repository;
|
||||
using Oqtane.Application.Repository;
|
||||
|
||||
namespace [Owner].Module.[Module].Services
|
||||
namespace Oqtane.Application.Services
|
||||
{
|
||||
public class Server[Module]Service : I[Module]Service
|
||||
public class ServerMyModuleService : IMyModuleService
|
||||
{
|
||||
private readonly I[Module]Repository _[Module]Repository;
|
||||
private readonly IMyModuleRepository _MyModuleRepository;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public Server[Module]Service(I[Module]Repository [Module]Repository, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger, IHttpContextAccessor accessor)
|
||||
public ServerMyModuleService(IMyModuleRepository MyModuleRepository, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger, IHttpContextAccessor accessor)
|
||||
{
|
||||
_[Module]Repository = [Module]Repository;
|
||||
_MyModuleRepository = MyModuleRepository;
|
||||
_userPermissions = userPermissions;
|
||||
_logger = logger;
|
||||
_accessor = accessor;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
public Task<List<Models.[Module]>> Get[Module]sAsync(int ModuleId)
|
||||
public Task<List<Models.MyModule>> GetMyModulesAsync(int ModuleId)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View))
|
||||
{
|
||||
return Task.FromResult(_[Module]Repository.Get[Module]s(ModuleId).ToList());
|
||||
return Task.FromResult(_MyModuleRepository.GetMyModules(ModuleId).ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Get Attempt {ModuleId}", ModuleId);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized MyModule Get Attempt {ModuleId}", ModuleId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<Models.[Module]> Get[Module]Async(int [Module]Id, int ModuleId)
|
||||
public Task<Models.MyModule> GetMyModuleAsync(int MyModuleId, int ModuleId)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View))
|
||||
{
|
||||
return Task.FromResult(_[Module]Repository.Get[Module]([Module]Id));
|
||||
return Task.FromResult(_MyModuleRepository.GetMyModule(MyModuleId));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Get Attempt {[Module]Id} {ModuleId}", [Module]Id, ModuleId);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized MyModule Get Attempt {TaskId} {ModuleId}", MyModuleId, ModuleId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<Models.[Module]> Add[Module]Async(Models.[Module] [Module])
|
||||
public Task<Models.MyModule> AddMyModuleAsync(Models.MyModule MyModule)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, [Module].ModuleId, PermissionNames.Edit))
|
||||
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, MyModule.ModuleId, PermissionNames.Edit))
|
||||
{
|
||||
[Module] = _[Module]Repository.Add[Module]([Module]);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "[Module] Added {[Module]}", [Module]);
|
||||
MyModule = _MyModuleRepository.AddMyModule(MyModule);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "MyModule Added {MyModule}", MyModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Add Attempt {[Module]}", [Module]);
|
||||
[Module] = null;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized MyModule Add Attempt {MyModule}", MyModule);
|
||||
MyModule = null;
|
||||
}
|
||||
return Task.FromResult([Module]);
|
||||
return Task.FromResult(MyModule);
|
||||
}
|
||||
|
||||
public Task<Models.[Module]> Update[Module]Async(Models.[Module] [Module])
|
||||
public Task<Models.MyModule> UpdateMyModuleAsync(Models.MyModule MyModule)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, [Module].ModuleId, PermissionNames.Edit))
|
||||
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, MyModule.ModuleId, PermissionNames.Edit))
|
||||
{
|
||||
[Module] = _[Module]Repository.Update[Module]([Module]);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "[Module] Updated {[Module]}", [Module]);
|
||||
MyModule = _MyModuleRepository.UpdateMyModule(MyModule);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "MyModule Updated {MyModule}", MyModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Update Attempt {[Module]}", [Module]);
|
||||
[Module] = null;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized MyModule Update Attempt {MyModule}", MyModule);
|
||||
MyModule = null;
|
||||
}
|
||||
return Task.FromResult([Module]);
|
||||
return Task.FromResult(MyModule);
|
||||
}
|
||||
|
||||
public Task Delete[Module]Async(int [Module]Id, int ModuleId)
|
||||
public Task DeleteMyModuleAsync(int MyModuleId, int ModuleId)
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.Edit))
|
||||
{
|
||||
_[Module]Repository.Delete[Module]([Module]Id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "[Module] Deleted {[Module]Id}", [Module]Id);
|
||||
_MyModuleRepository.DeleteMyModule(MyModuleId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "MyModule Deleted {MyModuleId}", MyModuleId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Delete Attempt {[Module]Id} {ModuleId}", [Module]Id, ModuleId);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized MyModule Delete Attempt {MyModuleId} {ModuleId}", MyModuleId, ModuleId);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
45
Oqtane.Application/Server/Startup.cs
Normal file
@ -0,0 +1,45 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,10 +2,10 @@ using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Oqtane.Infrastructure;
|
||||
using [Owner].Module.[Module].Repository;
|
||||
using [Owner].Module.[Module].Services;
|
||||
using Oqtane.Application.Repository;
|
||||
using Oqtane.Application.Services;
|
||||
|
||||
namespace [Owner].Module.[Module].Startup
|
||||
namespace Oqtane.Application.Startup
|
||||
{
|
||||
public class ServerStartup : IServerStartup
|
||||
{
|
||||
@ -21,8 +21,8 @@ namespace [Owner].Module.[Module].Startup
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<I[Module]Service, Server[Module]Service>();
|
||||
services.AddDbContextFactory<[Module]Context>(opt => { }, ServiceLifetime.Transient);
|
||||
services.AddTransient<IMyModuleService, ServerMyModuleService>();
|
||||
services.AddDbContextFactory<Context>(opt => { }, ServiceLifetime.Transient);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"RenderMode": "Interactive",
|
||||
"RenderMode": "Static",
|
||||
"Runtime": "Server",
|
||||
"Database": {
|
||||
"DefaultDBType": ""
|
||||
@ -22,27 +22,42 @@
|
||||
{
|
||||
"Name": "LocalDB",
|
||||
"ControlType": "Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client",
|
||||
"DBType": "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer"
|
||||
"DBType": "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server"
|
||||
},
|
||||
{
|
||||
"Name": "SQL Server",
|
||||
"ControlType": "Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client",
|
||||
"DBType": "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer"
|
||||
"DBType": "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server"
|
||||
},
|
||||
{
|
||||
"Name": "SQLite",
|
||||
"ControlType": "Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client",
|
||||
"DBType": "Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Database.Sqlite"
|
||||
"DBType": "Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Server"
|
||||
},
|
||||
{
|
||||
"Name": "MySQL",
|
||||
"ControlType": "Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client",
|
||||
"DBType": "Oqtane.Database.MySQL.MySQLDatabase, Oqtane.Database.MySQL"
|
||||
"DBType": "Oqtane.Database.MySQL.MySQLDatabase, Oqtane.Server"
|
||||
},
|
||||
{
|
||||
"Name": "PostgreSQL",
|
||||
"ControlType": "Oqtane.Installer.Controls.PostgreSQLConfig, Oqtane.Client",
|
||||
"DBType": "Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Database.PostgreSQL"
|
||||
"DBType": "Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Server"
|
||||
},
|
||||
{
|
||||
"Name": "Azure SQL",
|
||||
"ControlType": "Oqtane.Installer.Controls.AzureSqlConfig, Oqtane.Client",
|
||||
"DBType": "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server"
|
||||
}
|
||||
]
|
||||
],
|
||||
"Logging": {
|
||||
"FileLogger": {
|
||||
"LogLevel": {
|
||||
"Default": "Error"
|
||||
}
|
||||
},
|
||||
"LogLevel": {
|
||||
"Default": "Information"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
/* Module Script */
|
||||
var App = App || {};
|
||||
|
||||
App.MyModule = {
|
||||
};
|
@ -75,6 +75,10 @@ app {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.app-moduleactions .dropdown-menu {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.app-moduleactions .dropdown-submenu {
|
||||
position: relative;
|
||||
}
|
||||
@ -274,11 +278,11 @@ app {
|
||||
}
|
||||
|
||||
/* cookie consent */
|
||||
.gdpr-consent-bar .btn-show{
|
||||
.gdpr-consent-bar .btn-show {
|
||||
bottom: -3px;
|
||||
left: 5px;
|
||||
}
|
||||
.gdpr-consent-bar .btn-hide{
|
||||
.gdpr-consent-bar .btn-hide {
|
||||
top: 0;
|
||||
right: 5px;
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
@ -0,0 +1,22 @@
|
||||
.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;
|
||||
}
|
Before Width: | Height: | Size: 318 B After Width: | Height: | Size: 318 B |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 427 B After Width: | Height: | Size: 427 B |
BIN
Oqtane.Application/Server/wwwroot/images/disabled.png
Normal file
After Width: | Height: | Size: 875 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 801 B After Width: | Height: | Size: 801 B |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 177 B After Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 438 B |
@ -311,7 +311,7 @@ Oqtane.Interop = {
|
||||
}
|
||||
return files;
|
||||
},
|
||||
uploadFiles: async function (posturl, folder, id, antiforgerytoken, jwt, chunksize) {
|
||||
uploadFiles: async function (posturl, folder, id, antiforgerytoken, jwt, chunksize, anonymizeuploadfilenames) {
|
||||
var success = true;
|
||||
var fileinput = document.getElementById('FileInput_' + id);
|
||||
var progressinfo = document.getElementById('ProgressInfo_' + id);
|
||||
@ -344,16 +344,22 @@ Oqtane.Interop = {
|
||||
const totalParts = Math.ceil(file.size / chunkSize);
|
||||
let partCount = 0;
|
||||
|
||||
let filename = file.name;
|
||||
if (anonymizeuploadfilenames) {
|
||||
filename = crypto.randomUUID() + '.' + filename.split('.').pop();
|
||||
}
|
||||
|
||||
const uploadPart = () => {
|
||||
const start = partCount * chunkSize;
|
||||
const end = Math.min(start + chunkSize, file.size);
|
||||
const chunk = file.slice(start, end);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let formdata = new FormData();
|
||||
formdata.append('__RequestVerificationToken', antiforgerytoken);
|
||||
formdata.append('folder', folder);
|
||||
formdata.append('formfile', chunk, file.name);
|
||||
formdata.append('formfile', chunk, filename);
|
||||
|
||||
var credentials = 'same-origin';
|
||||
var headers = new Headers();
|
@ -0,0 +1,47 @@
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace [Owner].Module.[Module].Models
|
||||
namespace Oqtane.Application.Models
|
||||
{
|
||||
[Table("[Owner][Module]")]
|
||||
public class [Module] : IAuditable
|
||||
public class MyModule : IAuditable
|
||||
{
|
||||
[Key]
|
||||
public int [Module]Id { get; set; }
|
||||
public int MyModuleId { get; set; }
|
||||
public int ModuleId { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
13
Oqtane.Application/Shared/Oqtane.Application.Shared.csproj
Normal file
@ -0,0 +1,13 @@
|
||||
<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>
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
@ -1,8 +1,10 @@
|
||||
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
|
||||
{
|
||||
@ -23,7 +25,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddScoped<SiteState>();
|
||||
services.AddScoped<IInstallationService, InstallationService>();
|
||||
services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
|
||||
services.AddScoped<IThemeService, ThemeService>();
|
||||
services.AddScoped<IThemeService, Oqtane.Services.ThemeService>();
|
||||
services.AddScoped<IAliasService, AliasService>();
|
||||
services.AddScoped<ITenantService, TenantService>();
|
||||
services.AddScoped<ISiteService, SiteService>();
|
||||
@ -39,7 +41,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddScoped<ILogService, LogService>();
|
||||
services.AddScoped<IJobService, JobService>();
|
||||
services.AddScoped<IJobLogService, JobLogService>();
|
||||
services.AddScoped<INotificationService, NotificationService>();
|
||||
services.AddScoped<INotificationService, Oqtane.Services.NotificationService>();
|
||||
services.AddScoped<IFolderService, FolderService>();
|
||||
services.AddScoped<IFileService, FileService>();
|
||||
services.AddScoped<ISiteTemplateService, SiteTemplateService>();
|
||||
@ -53,12 +55,18 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddScoped<ISyncService, SyncService>();
|
||||
services.AddScoped<ILocalizationCookieService, LocalizationCookieService>();
|
||||
services.AddScoped<ICookieConsentService, CookieConsentService>();
|
||||
services.AddScoped<IOutputCacheService, OutputCacheService>();
|
||||
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
||||
services.AddScoped<IOutputCacheService, OutputCacheService>();
|
||||
|
||||
// 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="oqtane-black.png" />
|
||||
<img src="installer-logo.png" />
|
||||
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET @Environment.Version.Major)</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -182,7 +182,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
_databaseName = "LocalDB";
|
||||
_databaseName = Constants.DefaultDBName;
|
||||
}
|
||||
LoadDatabaseConfigComponent();
|
||||
|
||||
@ -269,8 +269,8 @@
|
||||
SiteName = Constants.DefaultSite,
|
||||
Register = _register,
|
||||
SiteTemplate = _template,
|
||||
RenderMode = RenderModes.Static,
|
||||
Runtime = Runtimes.Server
|
||||
RenderMode = "", // provided by appsettings.json
|
||||
Runtime = "" // provided by appsettings.json
|
||||
};
|
||||
|
||||
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" placeholder="hh:mm" @bind="@_startTime" />
|
||||
<input id="starting" type="time" class="form-control" @bind="@_startTime" placeholder="hh:mm" required="@(_startDate.HasValue)" />
|
||||
</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" />
|
||||
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" required="@(_endDate.HasValue)" />
|
||||
</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" />
|
||||
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" required="@(_nextDate.HasValue)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -176,10 +176,18 @@
|
||||
{
|
||||
job.Interval = int.Parse(_interval);
|
||||
}
|
||||
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));
|
||||
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);
|
||||
|
||||
try
|
||||
{
|
||||
@ -198,5 +206,4 @@
|
||||
AddModuleMessage(Localizer["Message.Required.JobInfo"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -116,11 +116,19 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
await JobService.StartJobAsync(jobId);
|
||||
await logger.LogInformation("Job Started {JobId}", jobId);
|
||||
AddModuleMessage(Localizer["Message.Job.Start"], MessageType.Success);
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
StateHasChanged();
|
||||
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();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -21,9 +21,7 @@ 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)
|
||||
{
|
||||
@ -49,15 +47,11 @@ 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>
|
||||
}
|
||||
}
|
||||
|