Compare commits

...

147 Commits

Author SHA1 Message Date
38f2fa5733 Merge pull request #735 from sbwalker/master
prepare for 1.0.4 release
2020-09-09 12:02:11 -04:00
7f15a5f464 prepare for 1.0.4 release 2020-09-09 12:01:16 -04:00
0c5d992d18 Merge pull request #52 from oqtane/master
sync
2020-09-09 11:49:45 -04:00
57dd983c1f Update README.md 2020-09-03 15:59:29 -04:00
d89927ca96 Update README.md 2020-09-02 15:20:17 -04:00
63744d9ec2 Update README.md 2020-09-02 15:17:56 -04:00
c67526b5b0 Update README.md 2020-09-01 16:44:33 -04:00
1cb6bf2a6b Merge pull request #724 from sbwalker/master
removed background color
2020-09-01 16:28:16 -04:00
ac9969c1b6 removed background color 2020-09-01 16:27:42 -04:00
510cd23d5e Update README.md 2020-09-01 16:24:27 -04:00
c94ccbff69 Merge pull request #723 from sbwalker/master
created architecture diagram
2020-09-01 16:23:21 -04:00
93d0cc5e1a created architecture diagram 2020-09-01 16:22:40 -04:00
075ea0aafd Merge pull request #51 from oqtane/master
sync
2020-08-31 10:04:27 -04:00
e75fe19103 Merge pull request #720 from sbwalker/master
add support for SVG and ICO files
2020-08-31 10:01:15 -04:00
e76f1b9663 use Label component in Module Creator templates 2020-08-31 10:00:30 -04:00
cb1c725ec1 add support for SVG and ICO files 2020-08-31 09:48:51 -04:00
98cd361fc0 Merge pull request #716 from sbwalker/master
enhanced Module Creator to allow developer to specify framework reference version so that modules can target any version including the local development environment
2020-08-29 11:30:53 -04:00
d0c8399dd9 enhanced Module Creator to allow developer to specify framework reference version so that modules can target any version including the local development environment 2020-08-29 11:30:16 -04:00
4effa8ec66 Merge pull request #715 from sbwalker/master
improved module/theme installation by saving the list of files which are in the Nuget package and using that list to remove them during uninstall
2020-08-29 10:56:26 -04:00
4065d87a74 improved module/theme installation by saving the list of files which are in the Nuget package and using that list to remove them during uninstall 2020-08-29 10:55:40 -04:00
eb9acc770c Merge pull request #714 from sbwalker/master
added support for dynamic inclusion of global resources in _host.cshtml ( ie. global stylesheets and scripts such as those required by UI component suites )
2020-08-28 11:25:38 -04:00
a8cd84e798 added support for dynamic inclusion of global resources in _host.cshtml ( ie. global stylesheets and scripts such as those required by UI component suites ) 2020-08-28 11:24:43 -04:00
74e5b83026 Merge pull request #711 from sbwalker/master
wired up JavaScript support in Module Creator templates
2020-08-27 17:17:32 -04:00
4aa0b83807 wired up JavaScript support in Module Creator templates 2020-08-27 17:16:54 -04:00
fd592e8d9f Merge pull request #707 from sbwalker/master
script file name should reflect next framework version
2020-08-26 15:25:54 -04:00
bb21eba39f script file name should reflect next major version 2020-08-26 15:24:44 -04:00
b09cb9d655 Merge pull request #50 from oqtane/master
sync
2020-08-26 15:16:28 -04:00
bbbe48b976 Merge pull request #700 from nohorse/patch-1
Create Tenant.01.00.02.02.sql
2020-08-26 15:08:35 -04:00
a036ee19a4 Merge pull request #698 from hishamco/logo
Fix logo
2020-08-26 15:02:43 -04:00
5b45c79357 Merge pull request #705 from sbwalker/master
Ensure folder does not contain files during deletion and remove directory during deletion, fix validation issue in add page which would allow a user to create a page without selecting a layout, modify action dialog to use its own CSS class name so it can be styled independently from the Admin Modal, rollback "container" CSS class assigment on panes
2020-08-26 15:01:09 -04:00
760fc3b8d4 Ensure folder does not contain files during deletion and remove directory during deletion, fix validation issue in add page which would allow a user to create a page without selecting a layout, modify action dialog to use its own CSS class name so it can be styled independently from the Admin Modal, rollback "container" CSS class assigment on panes 2020-08-26 15:00:07 -04:00
fc50a45ecd Create Tenant.01.00.02.02.sql
Proposed fixed for #699
2020-08-22 14:55:43 -07:00
e3fe8c5914 Fix logo 2020-08-22 04:19:11 +03:00
2624b9c105 Merge pull request #691 from mikecasas/plural-fix
Delete module pluralization in the location display.
2020-08-19 05:09:54 -07:00
2f9f823330 Delete module pluralization in the location display. 2020-08-18 17:02:40 -04:00
6cc144d733 Merge pull request #49 from oqtane/master
sync
2020-08-18 13:38:24 -07:00
df404c12a4 Merge pull request #686 from mikecasas/master
Add project reference for dotnet publish to work without errors.
2020-08-18 13:37:36 -07:00
faec53b3c5 Merge pull request #688 from mikecasas/patch-1
Rename MenuHorizontal.Razor to MenuHorizontal.razor
2020-08-18 13:37:23 -07:00
e1ec58b297 Rename MenuHorizontal.Razor to MenuHorizontal.razor 2020-08-18 09:34:26 -04:00
38738e0844 Add project reference for dotnet publish to work without errors. 2020-08-16 22:35:09 -04:00
abe0a1a806 Merge pull request #685 from sbwalker/master
resolved #604 - added support for renaming files and moving to a different folder. Also added support for renaming folders and moving to a different parent folder.
2020-08-16 16:03:10 -07:00
809946685a resolved #604 - added support for renaming files and moving to a different folder. Also added support for renaming folders and moving to a different parent folder. 2020-08-16 19:00:49 -04:00
20c8f1528d Merge pull request #683 from sbwalker/master
resolve #526 remove pluralization from module creation templates
2020-08-14 09:44:44 -07:00
282579fcf2 resolve #526 remove pluralization from module creation templates 2020-08-14 12:44:37 -04:00
c8e3fa88e7 Merge pull request #679 from sbwalker/master
Fix #676 - fix creation of new profile fields, add support for required and private profile fields, integrate field level help for consistency
2020-08-13 07:06:28 -07:00
aec5882de1 Fix #676 - fix creation of new profile fields, add support for required and private profile fields, integrate field level help for consistency 2020-08-13 10:06:15 -04:00
bc231b18cf Update README.md 2020-08-07 14:56:58 -04:00
6bcb769fe5 Merge pull request #675 from sbwalker/master
prepare for 1.0.3 release
2020-08-07 10:40:00 -07:00
90110a653c prepare for 1.0.3 release 2020-08-07 13:39:19 -04:00
3c561cc413 Merge pull request #48 from oqtane/master
sync
2020-08-07 10:25:15 -07:00
73f9622ba2 Merge pull request #674 from sbwalker/master
prepare for 1.0.3 release
2020-08-07 10:24:31 -07:00
cf198ff781 prepare for 1.0.3 release 2020-08-07 13:23:58 -04:00
648fc56495 Merge pull request #673 from sbwalker/master
fixed very large file upload
2020-08-07 08:46:57 -07:00
ea6dc6b983 fixed very large file upload 2020-08-07 11:46:11 -04:00
c0e8d09ce1 Merge pull request #672 from sbwalker/master
allow user to reinstall current version
2020-08-06 13:48:07 -07:00
a471784cf3 allow user to reinstall current version 2020-08-06 16:46:22 -04:00
1d2a4bf484 Merge pull request #671 from sbwalker/master
include logging during module and theme installation
2020-08-06 13:37:55 -07:00
3fa620f3bc include logging during module and theme installation 2020-08-06 16:37:27 -04:00
35f186b532 Merge pull request #670 from sbwalker/master
fix regression bug caused by #649 related to installing nupkg packages
2020-08-06 13:10:51 -07:00
5cf35fd70a fix regression bug caused by #649 related to installing nupkg packages 2020-08-06 16:10:19 -04:00
1eef08eaeb Merge pull request #669 from sbwalker/master
modifications for System Update
2020-08-06 10:30:40 -07:00
1750f28a9f modifications for System Update 2020-08-06 13:30:06 -04:00
41edbc5e22 Merge pull request #668 from sbwalker/master
modifications for System Update feature
2020-08-04 10:07:35 -07:00
04257f75e7 modifications for System Update feature 2020-08-04 13:06:54 -04:00
5fb602f733 Merge pull request #667 from sbwalker/master
Improvements to System Update
2020-08-04 05:48:19 -07:00
94f0bdcce9 Improvements to System Update 2020-08-04 08:47:39 -04:00
0ba24f9a3a Update README.md 2020-08-04 08:42:28 -04:00
aac7d6b97a Merge pull request #664 from sbwalker/master
create 1.0.2 packages
2020-07-23 15:32:17 -04:00
bcc33af52b create 1.0.2 packages 2020-07-23 15:31:28 -04:00
24fd42636a Merge pull request #663 from sbwalker/master
preparing for 1.0.2 release
2020-07-23 15:08:27 -04:00
8d539d058c preparing for 1.0.2 release 2020-07-23 15:07:18 -04:00
abda377f6f Merge pull request #662 from sbwalker/master
fix regression bug caused by #648  - the entries within a nupkg (zip) package use the '/' separator - the fix in #648 was causing a wwwroot\wwwroot\... folder to be created on Windows
2020-07-23 14:59:25 -04:00
51bf822392 fix regression bug caused by #648 - the entries within a nupkg (zip) package use the '/' separator - the fix in #648 was causing a wwwroot\wwwroot\... folder to be created on Windows 2020-07-23 14:58:33 -04:00
d3f135a9c7 Merge pull request #47 from oqtane/master
sync
2020-07-23 14:41:29 -04:00
07ba99cc41 Merge pull request #661 from sbwalker/master
increase wait time for browser redirects during app restarts
2020-07-23 14:40:46 -04:00
336550c571 increase wait time for browser redirects during app restarts 2020-07-23 14:39:53 -04:00
679cc04178 Merge pull request #660 from sbwalker/master
optimize NotificationJob so that it only processes the sites for each tenant once.
2020-07-23 14:15:24 -04:00
75fe4e7c89 optimize NotificationJob so that it only processes the sites for each tenant once. 2020-07-23 14:14:29 -04:00
410f8c74e5 Merge pull request #649 from JoergH66/feature/LoadDependDlls_InstallManager
Fixes 2 external module installation problems
2020-07-23 11:39:35 -04:00
05f67d6a2a Merge pull request #659 from sbwalker/master
fixed scheduler so that it does not set NextExecution until after the job has finished executing
2020-07-23 11:39:19 -04:00
3a6cde0e24 fixed scheduler so that it does not set NextExecution until after the job has finished executing 2020-07-23 11:38:20 -04:00
fe1de2b243 Merge pull request #658 from sbwalker/master
Allow scheduled jobs to set next execution date, fix issue in site settings where logo field was not being populated, fixed compositing issue where deleted modules were being rendered.
2020-07-22 16:10:23 -04:00
62a6b5f28a Allow scheduled jobs to set next execution date, fix issue in site settings where logo field was not being populated, fixed compositing issue where deleted modules were being rendered. 2020-07-22 16:09:39 -04:00
d648fa0f02 Merge pull request #657 from ADefWebserver/master
Make a Deploy to Azure Button #168
2020-07-21 11:07:36 -04:00
e706e8cf1f Update README.md
Points the button to the Oqtane repository
2020-07-18 09:55:27 -07:00
9eb8a7e65c Update azuredeploy.json 2020-07-18 09:40:40 -07:00
11c610edf0 Update .deployment 2020-07-18 09:18:02 -07:00
a65cdbd7ad Rename azure.deployment to .deployment 2020-07-18 08:12:18 -07:00
97c56ba142 Create azure.deployment 2020-07-18 08:02:03 -07:00
9fe72a1c98 Update azuredeploy.json 2020-07-17 18:45:57 -07:00
7b40725534 Update README.md 2020-07-17 18:15:08 -07:00
5e1671afe3 Create azuredeploy.json 2020-07-17 18:10:22 -07:00
50d74cbcee Merge pull request #656 from sbwalker/master
modifications to ActionLink and ActionDialog controls, added logic to prevent IHostedService from blocking startup, made controller route prefix consistent in module template
2020-07-17 15:11:32 -04:00
bc73e5e3d0 modifications to ActionLink and ActionDialog controls, added logic to prevent IHostedService from blocking startup, made controller route prefix consistent in module template 2020-07-17 15:09:05 -04:00
b02bdee8cb Merge pull request #46 from oqtane/master
sync
2020-07-17 10:10:23 -04:00
9db4985b14 Merge pull request #655 from alexhendel/fix-path-handling
Fix directory separator for path operations
2020-07-16 10:27:34 -04:00
6f281c256b Merge pull request #654 from mikecasas/upstream-local
Should be moduleid as the entity id is added in the CreateAuthPolicyU…
2020-07-16 10:27:19 -04:00
807252c9e5 Fix directory separator for path operations 2020-07-15 16:09:19 +02:00
23e7f66188 Delete module id as it is getting added in CreateAuthPolicyUrl method. 2020-07-14 11:47:59 -04:00
57c500f4bc Merge remote-tracking branch 'github-mike/upstream-local' into upstream-local 2020-07-14 11:42:55 -04:00
fe302aa9e4 Should be moduleid as the entity id is added in the CreateAuthPolicyUrl method. 2020-07-12 18:59:20 -04:00
f14f927df7 Update README.md 2020-07-09 10:19:20 -04:00
c3f74a5217 Update README.md 2020-07-09 10:18:06 -04:00
457d1bb563 Update README.md 2020-07-09 10:17:34 -04:00
25918056cb Update README.md 2020-07-09 10:14:53 -04:00
86517dd793 Update README.md 2020-07-09 10:13:07 -04:00
00ce083a2c Update README.md 2020-07-09 10:11:28 -04:00
bce262cd8e Merge pull request #652 from sbwalker/master
remove line feeds from content during import
2020-07-09 08:46:50 -04:00
b5db62ef6a remove line feeds from content during import 2020-07-09 08:45:23 -04:00
3703d87d50 Merge pull request #651 from sbwalker/master
Html encode job log messages, add new IModule property to allow modules to specify Runtime support, provide feedback during module content import, remove default EditMode option at the Page level (should be implemented at Module level) - resolves issue where Admin modules could not be deleted, include link to Event Log in AddModuleMessage for Error message type, fixed fallback support for themes in siterouter, integrated auth policy into site templates for Module Creator
2020-07-08 19:57:13 -04:00
f515def414 Html encode job log messages, add new IModule property to allow modules to specify Runtime support, provide feedback during module content import, remove default EditMode option at the Page level (should be implemented at Module level) - resolves issue where Admin modules could not be deleted, include link to Event Log in AddModuleMessage for Error message type, fixed fallback support for themes in siterouter, integrated auth policy into site templates for Module Creator 2020-07-08 19:56:02 -04:00
4bdf20822f check whether the file is in use, dependent runtime-dlls will distribute 2020-07-08 14:06:41 +02:00
49f4e64cb4 Merge pull request #45 from oqtane/master
sync
2020-07-07 08:44:51 -04:00
e615263706 Merge pull request #647 from chlupac/Notifications
Notification changes UNDO
2020-07-07 08:43:52 -04:00
2a7e256116 Merge pull request #648 from alexhendel/fix-linux-theme-installation
Fix directory separator in InstallationManager
2020-07-07 08:43:37 -04:00
a083405b48 Fix directory seperator in InstallationManager 2020-07-07 09:56:24 +02:00
3ea280c82a Motification changes UNDO 2020-07-06 15:27:35 +02:00
192433f02d Merge pull request #44 from oqtane/master
sync
2020-07-05 11:32:20 -04:00
56a2e9dcea Merge pull request #644 from chlupac/ActionIcons
Icons in module actions menu
2020-07-03 15:16:47 -04:00
921cced1c8 Merge pull request #643 from chlupac/Notifications
Notification job optimalization
2020-07-03 15:16:14 -04:00
b17f679f38 Notification job optimalization 2020-07-03 10:19:12 +02:00
8e43fcab21 Icons in module actions menu 2020-07-03 10:15:45 +02:00
73c5092e46 Merge pull request #43 from oqtane/master
sync
2020-07-02 08:56:55 -04:00
56537e4785 Merge pull request #642 from svreic/bugfix/page-path-validation
Page path validation
2020-07-02 08:13:39 -04:00
3bd7d7196d Merge pull request #640 from PoisnFang/routing
Url parameter helper enhancements
2020-07-02 08:11:14 -04:00
7b5a192b82 Added double page path validation 2020-07-02 09:47:42 +02:00
d4be058d07 Can get parameters without template
clear urlParameters dictionary if template fails. Removed UrlParametersTemplate property and UrlParamerters auto dictionary
2020-07-01 15:15:39 -07:00
6c20fea46a Merge pull request #641 from chlupac/NotifyRepo
Notification Repository Breaking change fix
2020-07-01 14:22:26 -04:00
2e7cfefb2e Notification Repository Breaking change fix 2020-07-01 14:23:55 +02:00
038894cf64 Enhancement to url parameters helper in modulebase 2020-07-01 01:35:06 -07:00
954e30d89f Save url parameter action segments 2020-06-30 16:01:16 -07:00
93d9c4534d Merge pull request #42 from oqtane/master
sync
2020-06-30 16:56:08 -04:00
468ca8c6a9 Merge pull request #639 from PoisnFang/routing
Hot fix for homepage routing
2020-06-30 16:54:54 -04:00
e7a4c08dea Now also properly routes in admin modules 2020-06-30 13:51:48 -07:00
69d639ee42 Hot fix for homepage routing 2020-06-30 13:42:35 -07:00
a780569a6f Merge pull request #41 from oqtane/master
sync
2020-06-30 16:16:11 -04:00
568c283efd Merge pull request #638 from PoisnFang/routing
Module Router Enhancement
2020-06-30 16:15:27 -04:00
fccdd07a08 Replaced token identifiers for { } 2020-06-30 12:59:19 -07:00
5e816ea912 Removed anchor property and hash is only set if there is anchor 2020-06-30 12:49:56 -07:00
cb2d529689 added in GetUrlParameters route to Module Index action 2020-06-30 04:16:08 -07:00
c5037e7084 Url parameters working on any page, plus queries and anchors 2020-06-30 03:41:35 -07:00
fdc39d57fb Module Router Enhancement
Allows for PageVariables through the URL
2020-06-27 11:49:24 -07:00
4960e2c668 Update README.md 2020-06-26 08:45:13 -04:00
66cc3a1392 Merge pull request #637 from sbwalker/master
improvements for custom authorization policy usage
2020-06-25 10:24:54 -04:00
6e7c8e7b05 improvements for custom authorization policy usage 2020-06-25 10:23:27 -04:00
727b943fa3 Merge pull request #636 from sbwalker/master
added ModuleControlBase
2020-06-25 09:32:56 -04:00
a4a0334ec0 added ModuleControlBase 2020-06-25 09:31:21 -04:00
159 changed files with 2081 additions and 986 deletions

2
.deployment Normal file
View File

@ -0,0 +1,2 @@
[config]
project = Oqtane.Server/Oqtane.Server.csproj

View File

@ -0,0 +1,111 @@
@namespace Oqtane.Modules.Admin.Files
@inherits ModuleBase
@inject IFileService FileService
@inject IFolderService FolderService
@inject NavigationManager NavigationManager
@if (_folders != null)
{
<table class="table table-borderless">
<tr>
<td>
<Label for="name" HelpText="The name of the file">Name: </Label>
</td>
<td>
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<Label For="parent" HelpText="The folder where the file is located">Folder: </Label>
</td>
<td>
<select id="parent" class="form-control" @bind="@_folderId">
@foreach (Folder folder in _folders)
{
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label for="size" HelpText="The size of the file (in bytes)">Size: </Label>
</td>
<td>
<input id="size" class="form-control" @bind="@_size" readonly />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveFile">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
}
@code {
private int _fileId = -1;
private string _name;
private List<Folder> _folders;
private int _folderId = -1;
private int _size;
private string _createdBy;
private DateTime _createdOn;
private string _modifiedBy;
private DateTime _modifiedOn;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
public override string Title => "File Management";
protected override async Task OnInitializedAsync()
{
try
{
_folders = await FolderService.GetFoldersAsync(PageState.Site.SiteId);
_fileId = Int32.Parse(PageState.QueryString["id"]);
File file = await FileService.GetFileAsync(_fileId);
if (file != null)
{
_name = file.Name;
_folderId = file.FolderId;
_size = file.Size;
_createdBy = file.CreatedBy;
_createdOn = file.CreatedOn;
_modifiedBy = file.ModifiedBy;
_modifiedOn = file.ModifiedOn;
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading File {FileId} {Error}", _fileId, ex.Message);
AddModuleMessage("Error Loading File", MessageType.Error);
}
}
private async Task SaveFile()
{
try
{
if (_name.IsPathOrFileValid())
{
File file = await FileService.GetFileAsync(_fileId);
file.Name = _name;
file.FolderId = _folderId;
file = await FileService.UpdateFileAsync(file);
await logger.LogInformation("File Saved {File}", file);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage("File Name Not Valid", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving File {FileId} {Error}", _fileId, ex.Message);
AddModuleMessage("Error Saving File", MessageType.Error);
}
}
}

View File

@ -1,6 +1,7 @@
@namespace Oqtane.Modules.Admin.Files
@inherits ModuleBase
@inject IFolderService FolderService
@inject IFileService FileService
@inject NavigationManager NavigationManager
@if (_folders != null)
@ -45,7 +46,7 @@
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@if (!_isSystem && PageState.QueryString.ContainsKey("id"))
{
<button type="button" class="btn btn-danger" @onclick="DeleteFolder">Delete</button>
<ActionDialog Header="Delete Folder" Message="@("Are You Sure You Wish To Delete This Folder?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFolder())" />
}
<br />
<br />
@ -123,7 +124,7 @@
AddModuleMessage("Folder Name Not Valid.", MessageType.Warning);
return;
}
try
{
Folder folder;
@ -174,7 +175,7 @@
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Folder {FolderId} {Error}", _folderId, ex.Message);
AddModuleMessage("Error Saving Module", MessageType.Error);
AddModuleMessage("Error Saving Folder", MessageType.Error);
}
}
@ -182,9 +183,33 @@
{
try
{
await FolderService.DeleteFolderAsync(_folderId);
await logger.LogInformation("Folder Deleted {Folder}", _folderId);
AddModuleMessage("Folder Deleted", MessageType.Success);
bool isparent = false;
foreach (Folder folder in _folders)
{
if (folder.ParentId == _folderId)
{
isparent = true;
break;
}
}
if (!isparent)
{
var files = await FileService.GetFilesAsync(_folderId);
if (files.Count == 0)
{
await FolderService.DeleteFolderAsync(_folderId);
await logger.LogInformation("Folder Deleted {Folder}", _folderId);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage("Folder Has Files And Cannot Be Deleted", MessageType.Warning);
}
}
else
{
AddModuleMessage("Folder Has Subfolders And Cannot Be Deleted", MessageType.Warning);
}
}
catch (Exception ex)
{

View File

@ -28,6 +28,7 @@
</table>
<Pager Items="@_files">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
<th>Modified</th>
@ -35,6 +36,7 @@
<th>Size</th>
</Header>
<Row>
<td><ActionLink Action="Details" Text="Edit" Parameters="@($"id=" + context.FileId.ToString())" /></td>
<td><ActionDialog Header="Delete File" Message="@("Are You Sure You Wish To Delete " + context.Name + "?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFile(context))" /></td>
<td><a href="@(ContentUrl(context.FileId))" target="_new">@context.Name</a></td>
<td>@context.ModifiedOn</td>

View File

@ -63,10 +63,18 @@
</tr>
<tr>
<td>
<Label For="retention-log" HelpText="What items do you want in the retention log">Retention Log (Items): </Label>
<Label For="retention" HelpText="Number of log entries to retain for this job">Retention Log (Items): </Label>
</td>
<td>
<input id="retention-log" class="form-control" @bind="@_retentionHistory" />
<input id="retention" class="form-control" @bind="@_retentionHistory" />
</td>
</tr>
<tr>
<td>
<Label For="next" HelpText="Next execution for this job.">Next Execution: </Label>
</td>
<td>
<input id="next" class="form-control" @bind="@_nextExecution" />
</td>
</tr>
</table>
@ -83,6 +91,7 @@
private string _startDate = string.Empty;
private string _endDate = string.Empty;
private string _retentionHistory = string.Empty;
private string _nextExecution = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
@ -102,6 +111,7 @@
_startDate = (job.StartDate != null) ? job.StartDate.ToString() : string.Empty;
_endDate = (job.EndDate != null) ? job.EndDate.ToString() : string.Empty;
_retentionHistory = job.RetentionHistory.ToString();
_nextExecution = job.NextExecution.ToString();
}
}
catch (Exception ex)
@ -140,6 +150,15 @@
job.EndDate = DateTime.Parse(_endDate);
}
if (_nextExecution == string.Empty)
{
job.NextExecution = null;
}
else
{
job.NextExecution = DateTime.Parse(_nextExecution);
}
job.RetentionHistory = int.Parse(_retentionHistory);
try

View File

@ -22,7 +22,7 @@ else
<td>@context.FinishDate</td>
</Row>
<Detail>
<td colspan="4">@context.Notes</td>
<td colspan="4">@((MarkupString)context.Notes)</td>
</Detail>
</Pager>
}

View File

@ -5,55 +5,69 @@
@inject IModuleService ModuleService
@inject ISystemService SystemService
<table class="table table-borderless">
<tr>
<td>
<Label For="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation.">Owner Name: </Label>
</td>
<td>
<input id="owner" class="form-control" @bind="@_owner" />
</td>
</tr>
<tr>
<td>
<Label For="module" HelpText="Enter a name for this module. It should be in singular form (ie. Car) and not contain spaces or punctuation.">Module Name: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_module" />
</td>
</tr>
<tr>
<td>
<Label For="description" HelpText="Enter s short description for the module">Description: </Label>
</td>
<td>
<textarea id="description" class="form-control" @bind="@_description" rows="3"></textarea>
</td>
</tr>
<tr>
<td>
<Label For="template" HelpText="Select a module template. Internal modules are created inside of the Oqtane solution. External modules are created outside of the Oqtane solution.">Template: </Label>
</td>
<td>
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
<option value="-">&lt;Select Template&gt;</option>
<option value="internal">Internal</option>
<option value="external">External</option>
</select>
</td>
</tr>
@if (!string.IsNullOrEmpty(_location))
{
<table class="table table-borderless">
<tr>
<td>
<Label For="location" HelpText="Location where the module will be created">Location: </Label>
<Label For="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation.">Owner Name: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_location" readonly />
<input id="owner" class="form-control" @bind="@_owner" />
</td>
</tr>
}
</table>
<tr>
<td>
<Label For="module" HelpText="Enter a name for this module. It should not contain spaces or punctuation.">Module Name: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_module" />
</td>
</tr>
<tr>
<td>
<Label For="description" HelpText="Enter s short description for the module">Description: </Label>
</td>
<td>
<textarea id="description" class="form-control" @bind="@_description" rows="3"></textarea>
</td>
</tr>
<tr>
<td>
<Label For="template" HelpText="Select a module template. Internal modules are created inside of the Oqtane solution. External modules are created outside of the Oqtane solution.">Template: </Label>
</td>
<td>
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
<option value="-">&lt;Select Template&gt;</option>
<option value="internal">Internal</option>
<option value="external">External</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="reference" HelpText="Select a framework reference version">Framework Reference: </Label>
</td>
<td>
<select id="reference" class="form-control" @bind="@_reference">
@foreach (string version in Constants.ReleaseVersions.Split(','))
{
<option value="@(version)">@(version)</option>
}
<option value="local">Local</option>
</select>
</td>
</tr>
@if (!string.IsNullOrEmpty(_location))
{
<tr>
<td>
<Label For="location" HelpText="Location where the module will be created">Location: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_location" readonly />
</td>
</tr>
}
</table>
<button type="button" class="btn btn-success" @onclick="CreateModule">Create Module</button>
@ -62,6 +76,7 @@
private string _module = string.Empty;
private string _description = string.Empty;
private string _template = "-";
public string _reference = Constants.Version;
private string _location = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
@ -77,7 +92,7 @@
{
if (!string.IsNullOrEmpty(_owner) && !string.IsNullOrEmpty(_module) && _template != "-")
{
var moduleDefinition = new ModuleDefinition { Owner = _owner.Replace(" ", ""), Name = _module.Replace(" ", ""), Description = _description, Template = _template };
var moduleDefinition = new ModuleDefinition { Owner = _owner.Replace(" ", ""), Name = _module.Replace(" ", ""), Description = _description, Template = _template, Version = _reference };
await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition, ModuleState.ModuleId);
}
else
@ -105,11 +120,11 @@
string[] path = systeminfo["serverpath"].Split('\\');
if (_template == "internal")
{
_location = string.Join("\\", path, 0, path.Length - 1) + "\\Oqtane.Client\\Modules\\" + _owner + "." + _module + "s";
_location = string.Join("\\", path, 0, path.Length - 1) + "\\Oqtane.Client\\Modules\\" + _owner + "." + _module;
}
else
{
_location = string.Join("\\", path, 0, path.Length - 2) + "\\" + _owner + "." + _module + "s";
_location = string.Join("\\", path, 0, path.Length - 2) + "\\" + _owner + "." + _module;
}
}
}

View File

@ -79,7 +79,7 @@
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await interop.RedirectBrowser(NavigateUrl(), 10);
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
}
catch (Exception ex)

View File

@ -75,12 +75,20 @@
</tr>
<tr>
<td>
<Label For="license" HelpText="The license of the module">License: </Label>
<Label For="license" HelpText="The module license terms">License: </Label>
</td>
<td>
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
</td>
</tr>
<tr>
<td>
<Label For="runtimes" HelpText="The Blazor runtimes which this module supports">Runtimes: </Label>
</td>
<td>
<input id="runtimes" class="form-control" @bind="@_runtimes" disabled />
</td>
</tr>
</table>
</Section>
</TabPanel>
@ -110,6 +118,7 @@
private string _url = "";
private string _contact = "";
private string _license = "";
private string _runtimes = "";
private string _permissions;
private string _createdby;
private DateTime _createdon;
@ -139,6 +148,7 @@
_url = moduleDefinition.Url;
_contact = moduleDefinition.Contact;
_license = moduleDefinition.License;
_runtimes = moduleDefinition.Runtimes;
_permissions = moduleDefinition.Permissions;
_createdby = moduleDefinition.CreatedBy;
_createdon = moduleDefinition.CreatedOn;

View File

@ -86,7 +86,7 @@ else
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", moduledefinitionname, version);
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await interop.RedirectBrowser(NavigateUrl(), 10);
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
}
catch (Exception ex)
@ -102,7 +102,7 @@ else
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await interop.RedirectBrowser(NavigateUrl(), 10);
await ModuleDefinitionService.DeleteModuleDefinitionAsync(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId);
}
catch (Exception ex)

View File

@ -31,9 +31,15 @@
{
try
{
await ModuleService.ImportModuleAsync(ModuleState.ModuleId, _content);
StateHasChanged();
NavigationManager.NavigateTo(NavigateUrl());
bool success = await ModuleService.ImportModuleAsync(ModuleState.ModuleId, _content);
if (success)
{
AddModuleMessage("Content Imported Successfully", MessageType.Success);
}
else
{
AddModuleMessage("A Problem Was Encountered Importing Content. Please Ensure The Content Is Formatted Correctly For The Module.", MessageType.Warning);
}
}
catch (Exception ex)
{

View File

@ -162,17 +162,6 @@
<input id="Icon" class="form-control" @bind="@_icon" />
</td>
</tr>
<tr>
<td>
<Label For="Default-Mode" HelpText="Select the default administration mode you want for this page">Default Mode? </Label>
</td>
<td>
<select id="Default-Mode" class="form-control" @bind="@_mode">
<option value="view">View Mode</option>
<option value="edit">Edit Mode</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="Personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content">Personalizable? </Label>
@ -217,7 +206,6 @@
private string _isnavigation = "True";
private string _url;
private string _ispersonalizable = "False";
private string _mode = "view";
private string _themetype = "-";
private string _layouttype = "-";
private string _containertype = "-";
@ -311,7 +299,7 @@
Page page = null;
try
{
if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && (_layouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)))
if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && (_layouts.Count == 0 || _layouttype != "-"))
{
page = new Page();
page.SiteId = PageState.Page.SiteId;
@ -346,6 +334,12 @@
}
}
if (!PagePathIsUnique(page.Path, page.SiteId, _pageList))
{
AddModuleMessage($"A page with path {_path} already exists for the selected parent page. The page path needs to be unique for the selected parent.", MessageType.Warning);
return;
}
Page child;
switch (_insert)
{
@ -367,7 +361,6 @@
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
page.Url = _url;
page.EditMode = (_mode == "edit" ? true : false);
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
{
@ -396,7 +389,7 @@
}
else
{
AddModuleMessage("You Must Provide Page Name And Theme", MessageType.Warning);
AddModuleMessage("You Must Provide Page Name And Theme/Layout", MessageType.Warning);
}
}
@ -407,4 +400,8 @@
}
}
private static bool PagePathIsUnique(string pagePath, int siteId, List<Page> existingPages)
{
return !existingPages.Any(page => page.SiteId == siteId && page.Path == pagePath);
}
}

View File

@ -173,17 +173,6 @@
<input id="Icon" class="form-control" @bind="@_icon" />
</td>
</tr>
<tr>
<td>
<Label For="Default-Mode" HelpText="Select the default administration mode you want for this page">Default Mode? </Label>
</td>
<td>
<select id="Default-Mode" class="form-control" @bind="@_mode">
<option value="view">View Mode</option>
<option value="edit">Edit Mode</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="Personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content">Personalizable? </Label>
@ -235,7 +224,6 @@
private string _isnavigation;
private string _url;
private string _ispersonalizable;
private string _mode;
private string _themetype = "-";
private string _layouttype = "-";
private string _containertype = "-";
@ -290,7 +278,6 @@
_isnavigation = page.IsNavigation.ToString();
_url = page.Url;
_ispersonalizable = page.IsPersonalizable.ToString();
_mode = (page.EditMode) ? "edit" : "view";
_themetype = page.ThemeType;
if (_themetype == PageState.Site.DefaultThemeType)
{
@ -333,7 +320,7 @@
_children = new List<Page>();
if (_parentid == "-1")
{
foreach(Page p in PageState.Pages.Where(item => item.ParentId == null))
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
@ -433,6 +420,13 @@
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
}
}
if (!PagePathIsUnique(page.Path, page.SiteId, page.PageId, _pageList))
{
AddModuleMessage($"A page with path {_path} already exists for the selected parent page. The page path needs to be unique for the selected parent.", MessageType.Warning);
return;
}
if (_insert != "=")
{
Page child;
@ -456,7 +450,6 @@
}
page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation));
page.Url = _url;
page.EditMode = (_mode == "edit");
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
{
@ -512,4 +505,9 @@
AddModuleMessage("Error Saving Page", MessageType.Error);
}
}
private static bool PagePathIsUnique(string pagePath, int siteId, int pageId, List<Page> existingPages)
{
return !existingPages.Any(page => page.SiteId == siteId && page.Path == pagePath && page.PageId != pageId);
}
}

View File

@ -145,6 +145,7 @@
profile = new Profile();
}
profile.SiteId = PageState.Site.SiteId;
profile.Name = _name;
profile.Title = _title;
profile.Description = _description;

View File

@ -7,7 +7,7 @@
@inject IThemeService ThemeService
@inject ISettingService SettingService
@if (_themes != null)
@if (_initialized)
{
<table class="table table-borderless">
<tr>
@ -211,6 +211,7 @@
}
@code {
private bool _initialized = false;
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
@ -318,6 +319,8 @@
_deletedby = site.DeletedBy;
_deletedon = site.DeletedOn;
_isdeleted = site.IsDeleted.ToString();
_initialized = true;
}
}
catch (Exception ex)
@ -445,7 +448,7 @@
}
else
{
AddModuleMessage("You Must Provide A Site Name, Alias, And Default Theme/Container", MessageType.Warning);
AddModuleMessage("You Must Provide A Site Name, Alias, And Default Theme/Layout/Container", MessageType.Warning);
}
}
catch (Exception ex)

View File

@ -402,7 +402,7 @@ else
}
else
{
AddModuleMessage("You Must Provide A Tenant, Site Name, Alias, Default Theme/Container, And Site Template", MessageType.Warning);
AddModuleMessage("You Must Provide A Tenant, Site Name, Alias, Default Theme/Layout/Container, And Site Template", MessageType.Warning);
}
}
}

View File

@ -6,7 +6,7 @@
@inject IAliasService AliasService
@inject IThemeService ThemeService
@if (_themes != null)
@if (_initialized)
{
<table class="table table-borderless">
<tr>
@ -106,6 +106,7 @@
}
@code {
private bool _initialized = false;
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
@ -163,6 +164,8 @@
_deletedby = site.DeletedBy;
_deletedon = site.DeletedOn;
_isdeleted = site.IsDeleted.ToString();
_initialized = true;
}
}
catch (Exception ex)

View File

@ -79,7 +79,7 @@
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await interop.RedirectBrowser(NavigateUrl(), 10);
await ThemeService.InstallThemesAsync();
}
catch (Exception ex)

View File

@ -87,7 +87,7 @@ else
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", themename, version);
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await interop.RedirectBrowser(NavigateUrl(), 10);
await ThemeService.InstallThemesAsync();
}
catch (Exception ex)
@ -103,7 +103,7 @@ else
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await interop.RedirectBrowser(NavigateUrl(), 10);
await ThemeService.DeleteThemeAsync(Theme.ThemeName);
}
catch (Exception ex)

View File

@ -12,7 +12,7 @@
@if (_upgradeavailable)
{
<ModuleMessage Type="MessageType.Info" Message="Select The Upgrade Button To Install a New Framework Version"></ModuleMessage>
@("Framework") @_package.Version <button type="button" class="btn btn-success" @onclick=@(async () => await Download(Constants.PackageId, Constants.Version))>Upgrade</button>
<button type="button" class="btn btn-success" @onclick=@(async () => await Download(Constants.PackageId, @_package.Version))>Upgrade To @_package.Version</button>
}
else
{
@ -26,7 +26,7 @@
<Label HelpText="Upload a framework package and select Install to complete the installation">Framework: </Label>
</td>
<td>
<FileManager Filter="nupkg" Folder="Framework" />
<FileManager Filter="nupkg" ShowFiles="false" Folder="Framework" />
</td>
</tr>
</table>
@ -71,7 +71,7 @@
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await interop.RedirectBrowser(NavigateUrl(), 10);
await InstallationService.Upgrade();
}
catch (Exception ex)
@ -88,7 +88,7 @@
await PackageService.DownloadPackageAsync(packageid, version, "Framework");
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await interop.RedirectBrowser(NavigateUrl(), 10);
await InstallationService.Upgrade();
}
catch (Exception ex)

View File

@ -75,10 +75,12 @@ else
<TabPanel Name="Profile">
@if (profiles != null && settings != null)
{
<table class="table table-borderless">
@foreach (Profile profile in profiles)
<table class="table table-borderless">
@foreach (Profile profile in profiles)
{
var p = profile;
if (!p.IsPrivate || UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole))
{
var p = profile;
if (p.Category != category)
{
<tr>
@ -90,14 +92,22 @@ else
}
<tr>
<td>
<label for="@p.Name" class="control-label">@p.Title: </label>
<Label For="@p.Name" HelpText="@p.Description">@p.Title</Label>
</td>
<td>
<input class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" placeholder="@p.Description" @onchange="@(e => ProfileChanged(e, p.Name))" />
@if (p.IsRequired)
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
}
</td>
</tr>
}
</table>
}
</table>
<button type="button" class="btn btn-primary" @onclick="Save">Save</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
}
@ -241,7 +251,7 @@ else
{
try
{
if (username != string.Empty && email != string.Empty)
if (username != string.Empty && email != string.Empty && ValidateProfiles())
{
if (password == confirm)
{
@ -261,6 +271,7 @@ else
await UserService.UpdateUserAsync(user);
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
await logger.LogInformation("User Profile Saved");
AddModuleMessage("User Profile Updated Successfully", MessageType.Success);
}
else
{
@ -269,7 +280,7 @@ else
}
else
{
AddModuleMessage("You Must Provide A Username and Email Address", MessageType.Warning);
AddModuleMessage("You Must Provide A Username and Email Address As Well As All Required Profile Information", MessageType.Warning);
}
}
catch (Exception ex)
@ -279,6 +290,26 @@ else
}
}
private bool ValidateProfiles()
{
bool valid = true;
foreach (Profile profile in profiles)
{
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
{
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
}
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole))
{
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
{
valid = false;
}
}
}
return valid;
}
private void Cancel()
{
NavigationManager.NavigateTo(NavigateUrl(string.Empty));

View File

@ -71,10 +71,17 @@
}
<tr>
<td>
<label for="@p.Name" class="control-label">@p.Title: </label>
<Label For="@p.Name" HelpText="@p.Description">@p.Title</Label>
</td>
<td>
<input class="form-control" maxlength="@p.MaxLength" placeholder="@p.Description" @onchange="@(e => ProfileChanged(e, p.Name))" />
@if (p.IsRequired)
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
}
</td>
</tr>
}
@ -112,11 +119,14 @@
}
}
private string GetProfileValue(string SettingName, string DefaultValue)
=> SettingService.GetSetting(settings, SettingName, DefaultValue);
private async Task SaveUser()
{
try
{
if (username != string.Empty && password != string.Empty && confirm != string.Empty && email != string.Empty)
if (username != string.Empty && password != string.Empty && confirm != string.Empty && email != string.Empty && ValidateProfiles())
{
if (password == confirm)
{
@ -149,7 +159,7 @@
}
else
{
AddModuleMessage("You Must Provide A Username, Password, and Email Address", MessageType.Warning);
AddModuleMessage("You Must Provide A Username, Password, Email Address And All Required Profile Information", MessageType.Warning);
}
}
catch (Exception ex)
@ -159,6 +169,23 @@
}
}
private bool ValidateProfiles()
{
bool valid = true;
foreach (Profile profile in profiles)
{
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
{
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
}
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
{
valid = false;
}
}
return valid;
}
private void ProfileChanged(ChangeEventArgs e, string SettingName)
{
var value = (string)e.Value;

View File

@ -98,10 +98,17 @@ else
}
<tr>
<td>
<label for="@p.Name" class="control-label">@p.Title: </label>
<Label For="@p.Name" HelpText="@p.Description">@p.Title</Label>
</td>
<td>
<input class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" placeholder="@p.Description" @onchange="@(e => ProfileChanged(e, p.Name))" />
@if (p.IsRequired)
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
}
</td>
</tr>
}
@ -180,7 +187,7 @@ else
{
try
{
if (username != string.Empty && email != string.Empty)
if (username != string.Empty && email != string.Empty && ValidateProfiles())
{
if (password == confirm)
{
@ -213,7 +220,7 @@ else
}
else
{
AddModuleMessage("You Must Provide A Username, Password, and Email Address", MessageType.Warning);
AddModuleMessage("You Must Provide A Username, Password, Email Address, And All Required Profile Information", MessageType.Warning);
}
}
catch (Exception ex)
@ -223,6 +230,23 @@ else
}
}
private bool ValidateProfiles()
{
bool valid = true;
foreach (Profile profile in profiles)
{
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
{
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
}
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
{
valid = false;
}
}
return valid;
}
private void ProfileChanged(ChangeEventArgs e, string SettingName)
{
var value = (string)e.Value;

View File

@ -1,9 +1,9 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
@if (_visible)
{
<div class="app-admin-modal">
<div class="app-actiondialog">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
@ -40,7 +40,7 @@
@code {
private bool _visible = false;
private bool _editmode = true;
private bool _editmode = false;
private bool _authorized = false;
private string _iconSpan = string.Empty;
@ -66,7 +66,7 @@
public bool Disabled { get; set; } // optional
[Parameter]
public string EditMode { get; set; } // optional - specifies if a user must be in edit mode to see the action - default is true
public string EditMode { get; set; } // optional - specifies if an authorized user must be in edit mode to see the action - default is false
[Parameter]
public Action OnClick { get; set; } // required if an Action is specified - executes a method in the calling component
@ -84,6 +84,7 @@
{
Class = "btn btn-success";
}
if (!string.IsNullOrEmpty(EditMode))
{
_editmode = bool.Parse(EditMode);

View File

@ -1,6 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
@inject IUserService UserService
@if (_authorized)
@ -21,7 +20,7 @@
private string _parameters = string.Empty;
private string _classname = "btn btn-primary";
private string _style = string.Empty;
private bool _editmode = true;
private bool _editmode = false;
private bool _authorized = false;
private string _iconSpan = string.Empty;
@ -47,11 +46,11 @@
public bool Disabled { get; set; } // optional
[Parameter]
public string EditMode { get; set; } // optional - specifies if a user must be in edit mode to see the action - default is true
public string EditMode { get; set; } // optional - specifies if an authorized user must be in edit mode to see the action - default is false.
[Parameter]
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
[Parameter]
public bool IconOnly { get; set; } // optional - specifies only icon in link
@ -90,8 +89,8 @@
if (!string.IsNullOrEmpty(IconName))
{
_iconSpan = $"<span class=\"oi oi-{IconName}\"></span>{(IconOnly?"":"&nbsp")}";
_iconSpan = $"<span class=\"oi oi-{IconName}\"></span>{(IconOnly ? "" : "&nbsp")}";
}
_url = EditUrl(Action, _parameters);
@ -123,7 +122,7 @@
{
security = Security.Value;
}
switch (security)
{
case SecurityAccessLevel.Anonymous:
@ -143,7 +142,7 @@
break;
}
}
return authorized;
}
}

View File

@ -1,6 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
@if (_text != string.Empty)
{
@ -8,7 +7,7 @@
}
@code {
private string _text = string.Empty;
[Parameter]
@ -22,7 +21,7 @@
[Parameter]
public DateTime ModifiedOn { get; set; }
[Parameter]
public string DeletedBy { get; set; }
@ -41,51 +40,51 @@
if (!String.IsNullOrEmpty(CreatedBy) || CreatedOn != null)
{
_text += "<p style=\"" + Style + "\">Created ";
if (!String.IsNullOrEmpty(CreatedBy))
{
_text += " by <b>" + CreatedBy + "</b>";
}
if (CreatedOn != null)
{
_text += " on <b>" + CreatedOn.ToString("MMM dd yyyy HH:mm:ss") + "</b>";
}
_text += "</p>";
}
if (!String.IsNullOrEmpty(ModifiedBy) || ModifiedOn != null)
{
_text += "<p style=\"" + Style + "\">Last modified ";
if (!String.IsNullOrEmpty(ModifiedBy))
{
_text += " by <b>" + ModifiedBy + "</b>";
}
if (ModifiedOn != null)
{
_text += " on <b>" + ModifiedOn.ToString("MMM dd yyyy HH:mm:ss") + "</b>";
}
_text += "</p>";
}
if (!String.IsNullOrEmpty(DeletedBy) || DeletedOn.HasValue)
{
_text += "<p style=\"" + Style + "\">Deleted ";
if (!String.IsNullOrEmpty(DeletedBy))
{
_text += " by <b>" + DeletedBy + "</b>";
}
if (DeletedOn != null)
{
_text += " on <b>" + DeletedOn.Value.ToString("MMM dd yyyy HH:mm:ss") + "</b>";
}
_text += "</p>";
}
}

View File

@ -1,7 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
@inject IFolderService FolderService
@inject IFileService FileService
@ -56,16 +54,16 @@
<div>
@if (UploadMultiple)
{
<input type="file" id="@_fileinputid" name="file" accept="@_filter" multiple/>
<input type="file" id="@_fileinputid" name="file" accept="@_filter" multiple />
}
else
{
<input type="file" id="@_fileinputid" name="file" accept="@_filter"/>
<input type="file" id="@_fileinputid" name="file" accept="@_filter" />
}
<span id="@_progressinfoid"></span><progress id="@_progressbarid" style="width: 150px; visibility: hidden;"></progress>
<span class="float-right">
<button type="button" class="btn btn-success" @onclick="UploadFile">Upload</button>
@if (_showfiles && GetFileId() != -1)
@if (ShowFiles && GetFileId() != -1)
{
<button type="button" class="btn btn-danger" @onclick="DeleteFile">Delete</button>
}
@ -88,7 +86,6 @@
private string _id;
private List<Folder> _folders;
private List<File> _files = new List<File>();
private bool _showfiles = true;
private string _fileinputid = string.Empty;
private string _progressinfoid = string.Empty;
private string _progressbarid = string.Empty;
@ -134,7 +131,7 @@
if (!string.IsNullOrEmpty(Folder))
{
_folders = new List<Folder> {new Folder {FolderId = -1, Name = Folder}};
_folders = new List<Folder> { new Folder { FolderId = -1, Name = Folder } };
FolderId = -1;
}
else
@ -163,7 +160,7 @@
await GetFiles();
// create unique id for component
// create unique id for component
_guid = Guid.NewGuid().ToString("N");
_fileinputid = _guid + "FileInput";
_progressinfoid = _guid + "ProgressInfo";
@ -211,7 +208,7 @@
_message = string.Empty;
try
{
FolderId = int.Parse((string) e.Value);
FolderId = int.Parse((string)e.Value);
await GetFiles();
FileId = -1;
_image = string.Empty;
@ -227,7 +224,7 @@
private async Task FileChanged(ChangeEventArgs e)
{
_message = string.Empty;
FileId = int.Parse((string) e.Value);
FileId = int.Parse((string)e.Value);
await SetImage();
StateHasChanged();
@ -244,8 +241,8 @@
var maxwidth = 200;
var maxheight = 200;
var ratioX = (double) maxwidth / (double) file.ImageWidth;
var ratioY = (double) maxheight / (double) file.ImageHeight;
var ratioX = (double)maxwidth / (double)file.ImageWidth;
var ratioY = (double)maxheight / (double)file.ImageHeight;
var ratio = ratioX < ratioY ? ratioX : ratioY;
_image = "<img src=\"" + ContentUrl(FileId) + "\" alt=\"" + file.Name +

View File

@ -1,6 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
@if (!string.IsNullOrEmpty(HelpText))
{
@ -16,7 +15,7 @@ else
private string _closeLabel = "</label>";
[Parameter]
public RenderFragment ChildContent { get; set; }
public RenderFragment ChildContent { get; set; }
[Parameter]
public string For { get; set; } // optional - the id of the associated input control for accessibility
@ -34,12 +33,12 @@ else
{
_openLabel += " for=\"" + For + "\"";
}
if (!string.IsNullOrEmpty(Class))
{
_openLabel += " class=\"" + Class + "\"";
}
_openLabel += ">";
}
}

View File

@ -1,10 +1,16 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
@inject NavigationManager NavigationManager
@if (!string.IsNullOrEmpty(_message))
{
<div class="@_classname" role="alert">@_message</div>
<div class="@_classname" role="alert">
@_message
@if (Type == MessageType.Error && UserSecurity.IsAuthorized(PageState.User, Constants.HostRole))
{
@((MarkupString)"&nbsp;&nbsp;")<NavLink href="@NavigateUrl("admin/log")">View Details</NavLink>
}
</div>
<br />
}
@ -52,7 +58,7 @@
classname = "alert alert-danger";
break;
}
return classname;
}
}

View File

@ -1,41 +1,39 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@typeparam TableItem
@inherits ModuleControlBase
@typeparam TableItem
<p>
@if(Format == "Table")
@if (Format == "Table")
{
<table class="@Class">
<thead>
<tr>@Header</tr>
</thead>
<tbody>
<table class="@Class">
<thead>
<tr>@Header</tr>
</thead>
<tbody>
@foreach (var item in ItemList)
{
<tr>@Row(item)</tr>
@if (Detail != null)
{
<tr>@Detail(item)</tr>
}
}
</tbody>
</table>
}
@if (Format == "Grid")
{
<div class="@Class">
<div class="row">@Header</div>
@foreach (var item in ItemList)
{
<tr>@Row(item)</tr>
<div class="row">@Row(item)</div>
@if (Detail != null)
{
<tr>@Detail(item)</tr>
<div class="row">@Detail(item)</div>
}
}
</tbody>
</table>
}
@if(Format == "Grid")
{
<div class="@Class">
<div class="row">@Header</div>
@foreach (var item in ItemList)
{
<div class="row">@Row(item)</div>
@if (Detail != null)
{
<div class="row">@Detail(item)</div>
}
}
</div>
</div>
}
<div class="mx-auto text-center">
@if (_page > _maxPages)
@ -44,7 +42,7 @@
}
@if (_endPage > 1)
{
<button class="btn btn-secondary" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></button>
<button class="btn btn-secondary" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></button>
@for (int i = _startPage; i <= _endPage; i++)
{
var pager = i;
@ -105,7 +103,7 @@
{
Format = "Table";
}
if (string.IsNullOrEmpty(Class))
{
if (Format == "Table")
@ -117,7 +115,7 @@
Class = "container";
}
}
if (string.IsNullOrEmpty(PageSize))
{
_maxItems = 10;
@ -126,7 +124,7 @@
{
_maxItems = int.Parse(PageSize);
}
if (string.IsNullOrEmpty(DisplayPages))
{
_maxPages = 5;
@ -149,7 +147,7 @@
{
ItemList = Items.Skip((currentPage - 1) * _maxItems).Take(_maxItems);
_page = currentPage;
StateHasChanged();
}
@ -174,7 +172,7 @@
{
_endPage = _pages;
}
StateHasChanged();
}
else if (direction == "back")
@ -208,7 +206,7 @@
_page -= 1;
}
}
UpdateList(_page);
}
}

View File

@ -1,6 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
@inject IRoleService RoleService
@inject IUserService UserService
@ -39,7 +38,7 @@
<th scope="col">User</th>
@foreach (PermissionString permission in _permissions)
{
<th style="text-align: center; width: 1px;">@permission.PermissionName</th>
<th style="text-align: center; width: 1px;">@permission.PermissionName</th>
}
</tr>
</thead>
@ -48,7 +47,7 @@
{
string userid = "[" + user.UserId.ToString() + "]";
<tr>
<td >@user.DisplayName</td>
<td>@user.DisplayName</td>
@foreach (PermissionString permission in _permissions)
{
var p = permission;
@ -107,13 +106,13 @@
_roles.Insert(0, new Role { Name = Constants.AllUsersRole });
_permissions = new List<PermissionString>();
foreach (string permissionname in _permissionnames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
// initialize with admin role
_permissions.Add(new PermissionString { PermissionName = permissionname, Permissions = Constants.AdminRole });
}
if (!string.IsNullOrEmpty(Permissions))
{
// populate permissions
@ -123,7 +122,7 @@
{
_permissions[_permissions.FindIndex(item => item.PermissionName == permissionstring.PermissionName)].Permissions = permissionstring.Permissions;
}
if (permissionstring.Permissions.Contains("["))
{
foreach (string user in permissionstring.Permissions.Split(new char[] { '[' }, StringSplitOptions.RemoveEmptyEntries))
@ -183,7 +182,7 @@
_message = "Username Does Not Exist";
}
}
_username = string.Empty;
}
@ -209,7 +208,7 @@
case null:
break; // permission not specified
}
_permissions[_permissions.FindIndex(item => item.PermissionName == permissionName)].Permissions = string.Join(";", ids.ToArray());
}
}

View File

@ -1,6 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
<div class="row" style="margin-bottom: 50px;">
<div class="col">
@ -108,12 +107,12 @@
public string DebugLevel { get; set; } = "info";
public override List<Resource> Resources => new List<Resource>()
{
{
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill1.3.6.min.js" },
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" },
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" }
};
protected override void OnInitialized()
{
_content = Content; // raw HTML

View File

@ -1,6 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
<div class="d-flex">
<div>

View File

@ -1,6 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
@if (Name == Parent.ActiveTab)
{

View File

@ -1,6 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inherits ModuleControlBase
<CascadingValue Value="this">
<div class="container-fluid">

View File

@ -1,4 +1,5 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleControlBase
<img src="@_src" title="@_title" @onclick="SetValue" />
@ -38,7 +39,7 @@
_value = true;
break;
}
SetImage();
OnChange(_value);
}

View File

@ -7,7 +7,7 @@
@if (PageState.EditMode)
{
<br /><ActionLink Action="Edit" /><br /><br />
<br /><ActionLink Action="Edit" EditMode="true" /><br /><br />
}
@code {

View File

@ -21,23 +21,23 @@ namespace Oqtane.Modules.HtmlText.Services
public async Task<HtmlTextInfo> GetHtmlTextAsync(int moduleId)
{
var htmltext = await GetJsonAsync<List<HtmlTextInfo>>($"{ApiUrl}/{moduleId}?entityid={moduleId}");
var htmltext = await GetJsonAsync<List<HtmlTextInfo>>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", moduleId));
return htmltext.FirstOrDefault();
}
public async Task AddHtmlTextAsync(HtmlTextInfo htmlText)
{
await PostJsonAsync($"{ApiUrl}?entityid={htmlText.ModuleId}", htmlText);
await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", htmlText.ModuleId), htmlText);
}
public async Task UpdateHtmlTextAsync(HtmlTextInfo htmlText)
{
await PutJsonAsync($"{ApiUrl}/{htmlText.HtmlTextId}?entityid={htmlText.ModuleId}", htmlText);
await PutJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlText.HtmlTextId}", htmlText.ModuleId), htmlText);
}
public async Task DeleteHtmlTextAsync(int moduleId)
{
await DeleteAsync($"{ApiUrl}/{moduleId}?entityid={moduleId}");
await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", moduleId));
}
}
}

View File

@ -17,7 +17,7 @@ namespace Oqtane.Modules
private Logger _logger;
protected Logger logger => _logger ?? (_logger = new Logger(this));
[Inject]
protected ILogService LoggingService { get; set; }
@ -30,7 +30,7 @@ namespace Oqtane.Modules
[CascadingParameter]
protected Module ModuleState { get; set; }
[CascadingParameter]
[CascadingParameter]
protected ModuleInstance ModuleInstance { get; set; }
// optional interface properties
@ -62,7 +62,7 @@ namespace Oqtane.Modules
}
}
}
// path method
public string ModulePath()
@ -116,6 +116,54 @@ namespace Oqtane.Modules
return Utilities.ContentUrl(PageState.Alias, fileid);
}
public virtual Dictionary<string, string> GetUrlParameters(string parametersTemplate = "")
{
var urlParameters = new Dictionary<string, string>();
string[] templateSegments;
var parameters = PageState.UrlParameters.Split('/', StringSplitOptions.RemoveEmptyEntries);
var parameterId = 0;
if (string.IsNullOrEmpty(parametersTemplate))
{
for (int i = 0; i < parameters.Length; i++)
{
urlParameters.TryAdd("parameter" + i, parameters[i]);
}
}
else
{
templateSegments = parametersTemplate.Split('/', StringSplitOptions.RemoveEmptyEntries);
if (parameters.Length == templateSegments.Length)
{
for (int i = 0; i < parameters.Length; i++)
{
if (parameters.Length > i)
{
if (templateSegments[i] == parameters[i])
{
urlParameters.TryAdd("parameter" + parameterId, parameters[i]);
parameterId++;
}
else if (templateSegments[i].StartsWith("{") && templateSegments[i].EndsWith("}"))
{
var key = templateSegments[i].Replace("{", "");
key = key.Replace("}", "");
urlParameters.TryAdd(key, parameters[i]);
}
else
{
i = parameters.Length;
urlParameters.Clear();
}
}
}
}
}
return urlParameters;
}
// user feedback methods
public void AddModuleMessage(string message, MessageType type)
{
@ -154,12 +202,15 @@ namespace Oqtane.Modules
case "add":
logFunction = LogFunction.Create;
break;
case "edit":
logFunction = LogFunction.Update;
break;
case "delete":
logFunction = LogFunction.Delete;
break;
default:
logFunction = LogFunction.Read;
break;
@ -241,4 +292,4 @@ namespace Oqtane.Modules
}
}
}
}
}

View File

@ -0,0 +1,10 @@
using Oqtane.Shared;
namespace Oqtane.Modules
{
[OqtaneIgnore]
public abstract class ModuleControlBase : ModuleBase
{
}
}

View File

@ -6,7 +6,7 @@
<LangVersion>7.3</LangVersion>
<RazorLangVersion>3.0</RazorLangVersion>
<Configurations>Debug;Release</Configurations>
<Version>1.0.1</Version>
<Version>1.0.4</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -15,7 +15,7 @@
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<RepositoryUrl>https://github.com/oqtane</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.1</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.4</PackageReleaseNotes>
<RootNamespace>Oqtane</RootNamespace>
<IsPackable>true</IsPackable>
</PropertyGroup>

View File

@ -170,6 +170,19 @@ namespace Oqtane.Services
// can be used to override the default alias
public Alias Alias { get; set; }
// add entityid parameter to url for custom authorization policy
public string CreateAuthorizationPolicyUrl(string url, int entityId)
{
if (url.Contains("?"))
{
return url + "&entityid=" + entityId.ToString();
}
else
{
return url + "?entityid=" + entityId.ToString();
}
}
[Obsolete("This method is obsolete. Use CreateApiUrl(Alias alias, string serviceName) instead.", false)]
public string CreateApiUrl(Alias alias, string absoluteUri, string serviceName)
{

View File

@ -127,7 +127,10 @@
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.Permissions))
{
<option value="@moduledefinition.ModuleDefinitionName">@moduledefinition.Name</option>
if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
{
<option value="@moduledefinition.ModuleDefinitionName">@moduledefinition.Name</option>
}
}
}
</select>
@ -196,26 +199,17 @@
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) || (PageState.Page.IsPersonalizable && PageState.User != null))
{
@if (PageState.Page.EditMode)
if (PageState.EditMode)
{
<button type="button" class="btn @ButtonClass active" aria-pressed="true" autocomplete="off">
<button type="button" class="btn @ButtonClass active" data-toggle="button" aria-pressed="true" autocomplete="off" @onclick="(async () => await ToggleEditMode(PageState.EditMode))">
<span class="oi oi-pencil"></span>
</button>
}
else
{
if (PageState.EditMode)
{
<button type="button" class="btn @ButtonClass active" data-toggle="button" aria-pressed="true" autocomplete="off" @onclick="(async () => await ToggleEditMode(PageState.EditMode))">
<span class="oi oi-pencil"></span>
</button>
}
else
{
<button type="button" class="btn @ButtonClass" data-toggle="button" aria-pressed="false" autocomplete="off" @onclick="(async () => await ToggleEditMode(PageState.EditMode))">
<span class="oi oi-pencil"></span>
</button>
}
<button type="button" class="btn @ButtonClass" data-toggle="button" aria-pressed="false" autocomplete="off" @onclick="(async () => await ToggleEditMode(PageState.EditMode))">
<span class="oi oi-pencil"></span>
</button>
}
}

View File

@ -2,7 +2,7 @@
@inherits ModuleActionsBase
@attribute [OqtaneIgnore]
@if (PageState.EditMode && !PageState.Page.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions))
@if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions))
{
<div class="app-moduleactions">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"></a>
@ -15,9 +15,20 @@
}
else
{
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action))">@action.Name</a>
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action))">
@if (string.IsNullOrEmpty(action.Icon))
{
@((MarkupString) "&nbsp;&nbsp;");
}
else
{
<span class="oi oi-@action.Icon" aria-hidden="true"></span>
}
&nbsp;
@action.Name
</a>
}
}
</div>
</div>
}
}

View File

@ -19,7 +19,7 @@ namespace Oqtane.Themes.Controls
[Inject] public IPageModuleService PageModuleService { get; set; }
[Inject] public IModuleService ModuleService { get; set; }
protected List<ActionViewModel> Actions;
public List<ActionViewModel> Actions;
protected override void OnParametersSet()
{
@ -31,51 +31,52 @@ namespace Oqtane.Themes.Controls
var actionList = new List<ActionViewModel>();
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions))
{
actionList.Add(new ActionViewModel {Name = "Manage Settings", Action = async (u, m) => await Settings(u, m)});
actionList.Add(new ActionViewModel {Icon = Icons.Cog, Name = "Manage Settings", Action = async (u, m) => await Settings(u, m)});
if (UserSecurity.GetPermissionStrings(ModuleState.Permissions).FirstOrDefault(item => item.PermissionName == PermissionNames.View).Permissions.Split(';').Contains(Constants.AllUsersRole))
{
actionList.Add(new ActionViewModel { Name = "Unpublish Module", Action = async (s, m) => await Unpublish(s, m) });
actionList.Add(new ActionViewModel {Icon=Icons.CircleX, Name = "Unpublish Module", Action = async (s, m) => await Unpublish(s, m) });
}
else
{
actionList.Add(new ActionViewModel { Name = "Publish Module", Action = async (s, m) => await Publish(s, m) });
actionList.Add(new ActionViewModel {Icon=Icons.CircleCheck, Name = "Publish Module", Action = async (s, m) => await Publish(s, m) });
}
actionList.Add(new ActionViewModel { Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m) });
actionList.Add(new ActionViewModel {Icon=Icons.Trash, Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m) });
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.ServerManagerType != "")
{
actionList.Add(new ActionViewModel { Name = "" });
actionList.Add(new ActionViewModel {Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import")});
actionList.Add(new ActionViewModel {Name = "Export Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Export")});
actionList.Add(new ActionViewModel {Icon=Icons.CloudUpload, Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import")});
actionList.Add(new ActionViewModel {Icon = Icons.CloudDownload, Name = "Export Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Export")});
}
actionList.Add(new ActionViewModel {Name = ""});
if (ModuleState.PaneModuleIndex > 0)
{
actionList.Add(new ActionViewModel {Name = "Move To Top", Action = async (s, m) => await MoveTop(s, m)});
actionList.Add(new ActionViewModel {Icon = Icons.DataTransferUpload ,Name = "Move To Top", Action = async (s, m) => await MoveTop(s, m)});
}
if (ModuleState.PaneModuleIndex > 0)
{
actionList.Add(new ActionViewModel {Name = "Move Up", Action = async (s, m) => await MoveUp(s, m)});
actionList.Add(new ActionViewModel {Icon = Icons.ArrowThickTop, Name = "Move Up", Action = async (s, m) => await MoveUp(s, m)});
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actionList.Add(new ActionViewModel {Name = "Move Down", Action = async (s, m) => await MoveDown(s, m)});
actionList.Add(new ActionViewModel {Icon = Icons.ArrowThickBottom, Name = "Move Down", Action = async (s, m) => await MoveDown(s, m)});
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actionList.Add(new ActionViewModel {Name = "Move To Bottom", Action = async (s, m) => await MoveBottom(s, m)});
actionList.Add(new ActionViewModel {Icon = Icons.DataTransferDownload, Name = "Move To Bottom", Action = async (s, m) => await MoveBottom(s, m)});
}
foreach (string pane in PageState.Page.Panes)
{
if (pane != ModuleState.Pane)
{
actionList.Add(new ActionViewModel {Name = "Move To " + pane + " Pane", Action = async (s, m) => await MoveToPane(s, pane, m)});
actionList.Add(new ActionViewModel {Icon = Icons.AccountLogin, Name = "Move To " + pane + " Pane", Action = async (s, m) => await MoveToPane(s, pane, m)});
}
}
}
@ -202,8 +203,8 @@ namespace Oqtane.Themes.Controls
public class ActionViewModel
{
public string Icon { get; set; }
public string Name { set; get; }
public Func<string, PageModule, Task<string>> Action { set; get; }
}
}

View File

@ -19,7 +19,7 @@
{
_moduleState = Module; // passed in from Pane component
string container = _moduleState.ContainerType;
if (PageState.ModuleId != -1 && PageState.Action != "" && _moduleState.UseAdminContainer)
if (PageState.ModuleId != -1 && _moduleState.UseAdminContainer)
{
container = Constants.DefaultAdminContainer;
}

View File

@ -14,10 +14,11 @@ namespace Oqtane.UI
public List<Module> Modules { get; set; }
public Uri Uri { get; set; }
public Dictionary<string, string> QueryString { get; set; }
public string UrlParameters { get; set; }
public int ModuleId { get; set; }
public string Action { get; set; }
public bool EditMode { get; set; }
public DateTime LastSyncDate { get; set; }
public Runtime Runtime { get; set; }
}
}
}

View File

@ -1,4 +1,5 @@
@namespace Oqtane.UI
@using Microsoft.AspNetCore.Components.Rendering
@namespace Oqtane.UI
@inject IUserService UserService
@inject IModuleService ModuleService
@inject IModuleDefinitionService ModuleDefinitionService
@ -25,25 +26,25 @@
protected override void OnParametersSet()
{
if (PageState.EditMode && !PageState.Page.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, PageState.Page.Permissions) && Name != Constants.AdminPane)
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, PageState.Page.Permissions) && Name != Constants.AdminPane)
{
_paneadminborder = "app-pane-admin-border";
_panetitle = "<div class=\"app-pane-admin-title\">" + Name + " Pane</div>";
}
else
{
_paneadminborder = "container";
_paneadminborder = "";
_panetitle = "";
}
DynamicComponent = builder =>
{
if (PageState.ModuleId != -1 && PageState.Action != "")
if (PageState.ModuleId != -1 && PageState.Action != Constants.DefaultAction)
{
if (Name.ToLower() == Constants.AdminPane.ToLower())
{
Module module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId);
if (module != null)
if (module != null && !module.IsDeleted)
{
var typename = module.ModuleType;
// check for core module actions component
@ -51,7 +52,7 @@
{
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, PageState.Action);
}
var moduleType = Type.GetType(typename);
if (moduleType != null)
{
@ -88,10 +89,7 @@
{
module.Title = module.ControlTitle;
}
builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent));
builder.AddAttribute(1, "Module", module);
builder.CloseComponent();
CreateComponent(builder, module);
}
}
else
@ -106,14 +104,12 @@
if (PageState.ModuleId != -1)
{
Module module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId);
if (module != null && module.Pane.ToLower() == Name.ToLower())
if (module != null && module.Pane.ToLower() == Name.ToLower() && !module.IsDeleted)
{
// check if user is authorized to view module
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
{
builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent));
builder.AddAttribute(1, "Module", module);
builder.CloseComponent();
CreateComponent(builder, module);
}
}
}
@ -124,14 +120,19 @@
// check if user is authorized to view module
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
{
builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent));
builder.AddAttribute(1, "Module", module);
builder.SetKey(module.PageModuleId);
builder.CloseComponent();
CreateComponent(builder, module);
}
}
}
}
};
}
private void CreateComponent(RenderTreeBuilder builder, Module module)
{
builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent));
builder.AddAttribute(1, "Module", module);
builder.SetKey(module.PageModuleId);
builder.CloseComponent();
}
}

View File

@ -76,7 +76,8 @@
User user = null;
List<Module> modules;
var moduleid = -1;
var action = "";
var action = string.Empty;
var urlparameters = string.Empty;
var editmode = false;
var reload = Reload.None;
var lastsyncdate = DateTime.UtcNow;
@ -179,21 +180,60 @@
// extract admin route elements from path
var segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
int result;
// check if path has moduleid and action specification ie. pagename/moduleid/action/
if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result))
int modIdPos = 0;
int actionPos = 0;
int urlParametersPos = 0;
for (int i = 0; i < segments.Length; i++)
{
action = segments[segments.Length - 1];
moduleid = result;
path = path.Replace(moduleid.ToString() + "/" + action + "/", "");
}
else
{
// check if path has moduleid specification ie. pagename/moduleid/
if (segments.Length >= 1 && int.TryParse(segments[segments.Length - 1], out result))
if (segments[i] == Constants.UrlParametersDelimiter)
{
moduleid = result;
path = path.Replace(moduleid.ToString() + "/", "");
urlParametersPos = i + 1;
}
if (i >= urlParametersPos && urlParametersPos != 0)
{
urlparameters += "/" + segments[i];
}
if (segments[i] == Constants.ModuleDelimiter)
{
modIdPos = i + 1;
actionPos = modIdPos + 1;
if (actionPos > segments.Length - 1)
{
action = Constants.DefaultAction;
}
else
{
action = segments[actionPos];
}
}
}
// check if path has moduleid and action specification ie. pagename/moduleid/action/
if (modIdPos > 0)
{
int.TryParse(segments[modIdPos], out result);
moduleid = result;
if (actionPos > segments.Length - 1)
{
path = path.Replace(segments[modIdPos - 1] + "/" + segments[modIdPos] + "/", "");
}
else
{
path = path.Replace(segments[modIdPos - 1] + "/" + segments[modIdPos] + "/" + segments[actionPos] + "/", "");
}
}
if (urlParametersPos > 0)
{
path = path.Replace(segments[urlParametersPos - 1] + urlparameters + "/", "");
}
// remove trailing slash so it can be used as a key for Pages
@ -220,17 +260,14 @@
{
page = pages.Where(item => item.Path == path).FirstOrDefault();
reload = Reload.Page;
if (page != null)
{
editmode = page.EditMode;
}
editmode = false;
}
if (page != null)
{
if (PageState == null)
{
editmode = page.EditMode;
editmode = false;
}
// check if user is authorized to view page
@ -263,6 +300,7 @@
Modules = modules,
Uri = new Uri(_absoluteUri, UriKind.Absolute),
QueryString = querystring,
UrlParameters = urlparameters,
ModuleId = moduleid,
Action = action,
EditMode = editmode,
@ -360,6 +398,13 @@
string panes = "";
Type themetype = Type.GetType(page.ThemeType);
if (themetype == null)
{
// fallback
page.ThemeType = Constants.DefaultTheme;
page.LayoutType = Constants.DefaultLayout;
themetype = Type.GetType(Constants.DefaultTheme);
}
if (themetype != null)
{
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
@ -401,7 +446,7 @@
if (module.PageId == page.PageId || module.ModuleId == moduleid)
{
var typename = string.Empty;
if (module.ModuleDefinition != null)
if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(GetRuntime().ToString())))
{
typename = module.ModuleDefinition.ControlTypeTemplate;
}
@ -512,4 +557,4 @@
=> RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"))
? Runtime.WebAssembly
: Runtime.Server;
}
}

View File

@ -54,11 +54,6 @@
DynamicComponent = builder =>
{
var themeType = Type.GetType(PageState.Page.ThemeType);
if (themeType == null)
{
// fallback
themeType = Type.GetType(Constants.DefaultTheme);
}
builder.OpenComponent(0, themeType);
builder.CloseComponent();
};

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Oqtane.Client</id>
<version>1.0.1</version>
<version>1.0.4</version>
<authors>Shaun Walker</authors>
<owners>.NET Foundation</owners>
<title>Oqtane Framework</title>
@ -13,7 +13,7 @@
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<iconUrl>https://www.oqtane.org/Portals/0/icon.jpg</iconUrl>
<tags>oqtane</tags>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.1</releaseNotes>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.4</releaseNotes>
<summary>A modular application framework for Blazor</summary>
</metadata>
<files>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Oqtane.Framework</id>
<version>1.0.1</version>
<version>1.0.4</version>
<authors>Shaun Walker</authors>
<owners>.NET Foundation</owners>
<title>Oqtane Framework</title>
@ -13,16 +13,11 @@
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<iconUrl>https://www.oqtane.org/Portals/0/icon.jpg</iconUrl>
<tags>oqtane framework</tags>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.1</releaseNotes>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.4</releaseNotes>
<summary>A modular application framework for Blazor</summary>
</metadata>
<files>
<file src="..\Oqtane.Client\bin\Release\netstandard2.1\Oqtane.Client.dll" target="lib\netcoreapp3.1" />
<file src="..\Oqtane.Client\bin\Release\netstandard2.1\Oqtane.Client.pdb" target="lib\netcoreapp3.1" />
<file src="..\Oqtane.Server\bin\Release\netcoreapp3.1\Oqtane.Server.dll" target="lib\netcoreapp3.1" />
<file src="..\Oqtane.Server\bin\Release\netcoreapp3.1\Oqtane.Server.pdb" target="lib\netcoreapp3.1" />
<file src="..\Oqtane.Shared\bin\Release\netstandard2.1\Oqtane.Shared.dll" target="lib\netcoreapp3.1" />
<file src="..\Oqtane.Shared\bin\Release\netstandard2.1\Oqtane.Shared.pdb" target="lib\netcoreapp3.1" />
<file src="..\Oqtane.Server\wwwroot\**\*.*" target="wwwroot" />
<file src="..\Oqtane.Server\bin\Release\netcoreapp3.1\publish\*.*" target="lib\netcoreapp3.1" />
<file src="..\Oqtane.Server\bin\Release\netcoreapp3.1\publish\wwwroot\**\*.*" target="wwwroot" />
</files>
</package>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Oqtane.Server</id>
<version>1.0.1</version>
<version>1.0.4</version>
<authors>Shaun Walker</authors>
<owners>.NET Foundation</owners>
<title>Oqtane Framework</title>
@ -13,7 +13,7 @@
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<iconUrl>https://www.oqtane.org/Portals/0/icon.jpg</iconUrl>
<tags>oqtane</tags>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.1</releaseNotes>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.4</releaseNotes>
<summary>A modular application framework for Blazor</summary>
</metadata>
<files>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Oqtane.Shared</id>
<version>1.0.1</version>
<version>1.0.4</version>
<authors>Shaun Walker</authors>
<owners>.NET Foundation</owners>
<title>Oqtane Framework</title>
@ -13,7 +13,7 @@
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<iconUrl>https://www.oqtane.org/Portals/0/icon.jpg</iconUrl>
<tags>oqtane</tags>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.1</releaseNotes>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.4</releaseNotes>
<summary>A modular application framework for Blazor</summary>
</metadata>
<files>

View File

@ -0,0 +1 @@
Compress-Archive -Path "..\Oqtane.Server\bin\Release\netcoreapp3.1\publish\*" -DestinationPath "..\Oqtane.Server\bin\Release\Oqtane.Framework.1.0.4.Install.zip" -Force

Binary file not shown.

View File

@ -1,5 +1,18 @@
DEL "*.nupkg"
del "*.nupkg"
dotnet clean -c Release ..\Oqtane.sln
dotnet build -c Release ..\Oqtane.sln
dotnet pack -o .\ -c Release ..\Oqtane.sln
nuget.exe pack Oqtane.Framework.nuspec
nuget.exe pack Oqtane.Client.nuspec
nuget.exe pack Oqtane.Server.nuspec
nuget.exe pack Oqtane.Shared.nuspec
del /F/Q/S "..\Oqtane.Server\bin\Release\netcoreapp3.1\publish" > NUL
rmdir /Q/S "..\Oqtane.Server\bin\Release\netcoreapp3.1\publish"
dotnet publish ..\Oqtane.Server\Oqtane.Server.csproj /p:Configuration=Release
del "..\Oqtane.Server\bin\Release\netcoreapp3.1\publish\appsettings.json"
ren "..\Oqtane.Server\bin\Release\netcoreapp3.1\publish\appsettings.release.json" "appsettings.json"
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\install.ps1"
del "..\Oqtane.Server\bin\Release\netcoreapp3.1\publish\appsettings.json"
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\upgrade.ps1"
del "..\Oqtane.Server\bin\Release\netcoreapp3.1\publish\Oqtane.Upgrade.*"
nuget.exe pack Oqtane.Framework.nuspec

View File

@ -0,0 +1 @@
Compress-Archive -Path "..\Oqtane.Server\bin\Release\netcoreapp3.1\publish\*" -DestinationPath "..\Oqtane.Server\bin\Release\Oqtane.Framework.1.0.4.Upgrade.zip" -Force

View File

@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@ -135,8 +135,20 @@ namespace Oqtane.Controllers
[Authorize(Roles = Constants.RegisteredRole)]
public Models.File Put(int id, [FromBody] Models.File file)
{
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.Folder.FolderId, PermissionNames.Edit))
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.FolderId, PermissionNames.Edit))
{
file.Folder = _folders.GetFolder(file.FolderId);
Models.File _file = _files.GetFile(id, false);
if (_file.Name != file.Name || _file.FolderId != file.FolderId)
{
string folderpath = GetFolderPath(file.Folder);
if (!Directory.Exists(folderpath))
{
Directory.CreateDirectory(folderpath);
}
System.IO.File.Move(Path.Combine(GetFolderPath(_file.Folder), _file.Name), Path.Combine(folderpath, file.Name));
}
file.Extension = Path.GetExtension(file.Name).ToLower().Replace(".", "");
file = _files.UpdateFile(file);
_logger.Log(LogLevel.Information, this, LogFunction.Update, "File Updated {File}", file);
}
@ -483,7 +495,7 @@ namespace Oqtane.Controllers
string[] folders = folderpath.Split(separators, StringSplitOptions.RemoveEmptyEntries);
foreach (string folder in folders)
{
path = Utilities.PathCombine(path, folder, "\\");
path = Utilities.PathCombine(path, folder, Path.DirectorySeparatorChar.ToString());
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Oqtane.Models;
@ -10,20 +11,25 @@ using Oqtane.Extensions;
using Oqtane.Infrastructure;
using Oqtane.Repository;
using Oqtane.Security;
using Microsoft.AspNetCore.Hosting;
namespace Oqtane.Controllers
{
[Route("{alias}/api/[controller]")]
public class FolderController : Controller
{
private readonly IWebHostEnvironment _environment;
private readonly IFolderRepository _folders;
private readonly IUserPermissions _userPermissions;
private readonly ITenantResolver _tenants;
private readonly ILogManager _logger;
public FolderController(IFolderRepository folders, IUserPermissions userPermissions, ILogManager logger)
public FolderController(IWebHostEnvironment environment, IFolderRepository folders, IUserPermissions userPermissions, ITenantResolver tenants, ILogManager logger)
{
_environment = environment;
_folders = folders;
_userPermissions = userPermissions;
_tenants = tenants;
_logger = logger;
}
@ -112,7 +118,7 @@ namespace Oqtane.Controllers
Folder parent = _folders.GetFolder(folder.ParentId.Value);
folder.Path = Utilities.PathCombine(parent.Path, folder.Name);
}
folder.Path = Utilities.PathCombine(folder.Path, "\\");
folder.Path = Utilities.PathCombine(folder.Path, Path.DirectorySeparatorChar.ToString());
folder = _folders.AddFolder(folder);
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Added {Folder}", folder);
}
@ -142,12 +148,19 @@ namespace Oqtane.Controllers
{
if (folder.IsPathValid())
{
if (string.IsNullOrEmpty(folder.Path) && folder.ParentId != null)
if (folder.ParentId != null)
{
Folder parent = _folders.GetFolder(folder.ParentId.Value);
folder.Path = Utilities.PathCombine(parent.Path, folder.Name);
}
folder.Path = Utilities.PathCombine(folder.Path, "\\");
folder.Path = Utilities.PathCombine(folder.Path, Path.DirectorySeparatorChar.ToString());
Models.Folder _folder = _folders.GetFolder(id, false);
if (_folder.Path != folder.Path && Directory.Exists(GetFolderPath(_folder)))
{
Directory.Move(GetFolderPath(_folder), GetFolderPath(folder));
}
folder = _folders.UpdateFolder(folder);
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Folder Updated {Folder}", folder);
}
@ -201,6 +214,11 @@ namespace Oqtane.Controllers
{
if (_userPermissions.IsAuthorized(User, EntityNames.Folder, id, PermissionNames.Edit))
{
Models.Folder _folder = _folders.GetFolder(id, false);
if (Directory.Exists(GetFolderPath(_folder)))
{
Directory.Delete(GetFolderPath(_folder));
}
_folders.DeleteFolder(id);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Folder Deleted {FolderId}", id);
}
@ -210,5 +228,10 @@ namespace Oqtane.Controllers
HttpContext.Response.StatusCode = 401;
}
}
private string GetFolderPath(Folder folder)
{
return Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", _tenants.GetTenant().TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path);
}
}
}

View File

@ -122,7 +122,7 @@ namespace Oqtane.Controllers
var pages = _pages.GetPages(module.SiteId).ToList();
foreach (Page page in pages)
{
if (page.PageId != pageModule.PageId && !page.EditMode)
if (page.PageId != pageModule.PageId && !page.Path.StartsWith("admin/"))
{
_pageModules.AddPageModule(new PageModule { PageId = page.PageId, ModuleId = pageModule.ModuleId, Title = pageModule.Title, Pane = pageModule.Pane, Order = pageModule.Order, ContainerType = pageModule.ContainerType });
}

View File

@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Oqtane.Infrastructure;
namespace Oqtane.Controllers
{
public class ModuleControllerBase : Controller
{
protected readonly ILogManager _logger;
protected int _entityId = -1; // passed as a querystring parameter for policy authorization and used for validation
public ModuleControllerBase(ILogManager logger, IHttpContextAccessor accessor)
{
_logger = logger;
if (accessor.HttpContext.Request.Query.ContainsKey("entityid"))
{
_entityId = int.Parse(accessor.HttpContext.Request.Query["entityid"]);
}
}
}
}

View File

@ -15,6 +15,7 @@ using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using System.Xml.Linq;
using System.Text.Json;
namespace Oqtane.Controllers
{
@ -94,8 +95,8 @@ namespace Oqtane.Controllers
[Authorize(Roles = Constants.HostRole)]
public void InstallModules()
{
_installationManager.InstallPackages("Modules", true);
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Modules Installed");
_installationManager.InstallPackages("Modules", true);
}
// DELETE api/<controller>/5?siteid=x
@ -110,6 +111,7 @@ namespace Oqtane.Controllers
{
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
// execute uninstall logic
foreach (Tenant tenant in _tenants.GetTenants())
{
try
@ -130,25 +132,28 @@ namespace Oqtane.Controllers
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "Error Uninstalling {ModuleDefinitionName} For Tenant {Tenant} {Error}", moduledefinition.ModuleDefinitionName, tenant.Name, ex.Message);
}
}
// use assets.json to clean up file resources
string assetfilepath = Path.Combine(_environment.WebRootPath, "Modules", Utilities.GetTypeName(moduledefinition.ModuleDefinitionName), "assets.json");
if (System.IO.File.Exists(assetfilepath))
{
List<string> assets = JsonSerializer.Deserialize<List<string>>(System.IO.File.ReadAllText(assetfilepath));
foreach(string asset in assets)
{
if (System.IO.File.Exists(asset))
{
System.IO.File.Delete(asset);
}
}
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assets Removed For {ModuleDefinitionName}", moduledefinition.ModuleDefinitionName);
}
// clean up module static resource folder
string folder = Path.Combine(_environment.WebRootPath, Path.Combine("Modules", Utilities.GetTypeName(moduledefinition.ModuleDefinitionName)));
if (Directory.Exists(folder))
{
Directory.Delete(folder, true);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Static Resources Removed For {ModuleDefinitionName}", moduledefinition.ModuleDefinitionName);
}
// get root assembly name ( note that this only works if modules follow a specific naming convention for their assemblies )
string assemblyname = Utilities.GetAssemblyName(moduledefinition.ModuleDefinitionName).ToLower();
assemblyname = assemblyname.Replace(".client", "").Replace(".oqtane", "");
// remove module assemblies from /bin
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
foreach (string file in Directory.EnumerateFiles(binfolder, assemblyname + "*.*"))
{
System.IO.File.Delete(file);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assembly {Filename} Removed For {ModuleDefinitionName}", file, moduledefinition.ModuleDefinitionName);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Resources Folder Removed For {ModuleDefinitionName}", moduledefinition.ModuleDefinitionName);
}
// remove module definition
@ -170,19 +175,19 @@ namespace Oqtane.Controllers
{
string rootPath;
DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath);
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", moduleDefinition.Template,"\\");
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", moduleDefinition.Template,Path.DirectorySeparatorChar.ToString());
if (moduleDefinition.Template == "internal")
{
rootPath = Utilities.PathCombine(rootFolder.FullName,"\\");
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + "s, Oqtane.Client";
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
rootPath = Utilities.PathCombine(rootFolder.FullName,Path.DirectorySeparatorChar.ToString());
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", Oqtane.Client";
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
}
else
{
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName , moduleDefinition.Owner + "." + moduleDefinition.Name + "s","\\");
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + "s, " + moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Client.Oqtane";
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Server.Oqtane";
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName , moduleDefinition.Owner + "." + moduleDefinition.Name,Path.DirectorySeparatorChar.ToString());
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane";
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane";
}
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition);
@ -196,8 +201,8 @@ namespace Oqtane.Controllers
{
// add embedded resources to project
List<string> resources = new List<string>();
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name + "s", "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + "s.1.0.0.sql"));
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name + "s", "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + "s.Uninstall.sql"));
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name, "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + ".1.0.0.sql"));
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name, "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + ".Uninstall.sql"));
EmbedResourceFiles(Utilities.PathCombine(rootPath, "Oqtane.Server", "Oqtane.Server.csproj"), resources);
}
@ -235,7 +240,20 @@ namespace Oqtane.Controllers
text = text.Replace("[ServerManagerType]", moduleDefinition.ServerManagerType);
text = text.Replace("[Folder]", folderPath);
text = text.Replace("[File]", Path.GetFileName(filePath));
text = text.Replace("[FrameworkVersion]", Constants.Version);
if (moduleDefinition.Version == "local")
{
text = text.Replace("[FrameworkVersion]", Constants.Version);
text = text.Replace("[ClientReference]", "<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\netcoreapp3.1\\Oqtane.Client.dll</HintPath></Reference>");
text = text.Replace("[ServerReference]", "<Reference Include=\"Oqtane.Server\"><HintPath>..\\..\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\netcoreapp3.1\\Oqtane.Server.dll</HintPath></Reference>");
text = text.Replace("[SharedReference]", "<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\netcoreapp3.1\\Oqtane.Shared.dll</HintPath></Reference>");
}
else
{
text = text.Replace("[FrameworkVersion]", moduleDefinition.Version);
text = text.Replace("[ClientReference]", "<PackageReference Include=\"Oqtane.Client\" Version=\"" + moduleDefinition.Version + "\" />");
text = text.Replace("[ServerReference]", "<PackageReference Include=\"Oqtane.Server\" Version=\"" + moduleDefinition.Version + "\" />");
text = text.Replace("[SharedReference]", "<PackageReference Include=\"Oqtane.Shared\" Version=\"" + moduleDefinition.Version + "\" />");
}
System.IO.File.WriteAllText(filePath, text);
}

View File

@ -125,7 +125,7 @@ namespace Oqtane.Controllers
_syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, page.SiteId);
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Page Added {Page}", page);
if (!page.EditMode)
if (!page.Path.StartsWith("admin/"))
{
var modules = _modules.GetModules(page.SiteId).Where(item => item.AllPages).ToList();
foreach (Module module in modules)
@ -163,7 +163,6 @@ namespace Oqtane.Controllers
page.Order = 0;
page.IsNavigation = false;
page.Url = "";
page.EditMode = false;
page.ThemeType = parent.ThemeType;
page.LayoutType = parent.LayoutType;
page.DefaultContainerType = parent.DefaultContainerType;

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Hosting;
using Oqtane.Enums;
using Oqtane.Infrastructure;
using Oqtane.Repository;
using System.Text.Json;
// ReSharper disable StringIndexOfIsCultureSpecific.1
@ -43,8 +44,8 @@ namespace Oqtane.Controllers
[Authorize(Roles = Constants.HostRole)]
public void InstallThemes()
{
_installationManager.InstallPackages("Themes", true);
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Themes Installed");
_installationManager.InstallPackages("Themes", true);
}
// DELETE api/<controller>/xxx
@ -56,19 +57,29 @@ namespace Oqtane.Controllers
Theme theme = themes.Where(item => item.ThemeName == themename).FirstOrDefault();
if (theme != null && Utilities.GetAssemblyName(theme.ThemeName) != "Oqtane.Client")
{
// use assets.json to clean up file resources
string assetfilepath = Path.Combine(_environment.WebRootPath, "Modules", Utilities.GetTypeName(theme.ThemeName), "assets.json");
if (System.IO.File.Exists(assetfilepath))
{
List<string> assets = JsonSerializer.Deserialize<List<string>>(System.IO.File.ReadAllText(assetfilepath));
foreach (string asset in assets)
{
if (System.IO.File.Exists(asset))
{
System.IO.File.Delete(asset);
}
}
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Assets Removed For {ThemeName}", theme.ThemeName);
}
// clean up theme static resource folder
string folder = Path.Combine(_environment.WebRootPath, "Themes" , Utilities.GetTypeName(theme.ThemeName));
if (Directory.Exists(folder))
{
Directory.Delete(folder, true);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Static Resources Removed For {ThemeName}", theme.ThemeName);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Resource Folder Removed For {ThemeName}", theme.ThemeName);
}
// remove theme assembly from /bin
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
System.IO.File.Delete(Path.Combine(binfolder, Utilities.GetAssemblyName(theme.ThemeName) + ".dll"));
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Assembly {Filename} Removed For {ThemeName}", Utilities.GetAssemblyName(theme.ThemeName) + ".dll", themename);
_installationManager.RestartApplication();
}
}

View File

@ -9,6 +9,7 @@ using System.Linq;
using System.Security.Claims;
using Oqtane.Shared;
using System;
using System.IO;
using System.Net;
using Oqtane.Enums;
using Oqtane.Infrastructure;
@ -174,7 +175,7 @@ namespace Oqtane.Controllers
}
// add folder for user
Folder folder = _folders.GetFolder(user.SiteId, Utilities.PathCombine("Users","\\"));
Folder folder = _folders.GetFolder(user.SiteId, Utilities.PathCombine("Users",Path.DirectorySeparatorChar.ToString()));
if (folder != null)
{
_folders.AddFolder(new Folder
@ -182,7 +183,7 @@ namespace Oqtane.Controllers
SiteId = folder.SiteId,
ParentId = folder.FolderId,
Name = "My Folder",
Path = Utilities.PathCombine(folder.Path, newUser.UserId.ToString(),"\\"),
Path = Utilities.PathCombine(folder.Path, newUser.UserId.ToString(),Path.DirectorySeparatorChar.ToString()),
Order = 1,
IsSystem = true,
Permissions = "[{\"PermissionName\":\"Browse\",\"Permissions\":\"[" + newUser.UserId.ToString() + "]\"},{\"PermissionName\":\"View\",\"Permissions\":\"All Users\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"[" +

View File

@ -342,46 +342,48 @@ namespace Oqtane.Infrastructure
if (!string.IsNullOrEmpty(moduledefinition.ReleaseVersions) && !string.IsNullOrEmpty(moduledefinition.ServerManagerType))
{
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
string[] versions = moduledefinition.ReleaseVersions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey))))
if (moduletype != null)
{
foreach (var tenant in db.Tenant.ToList())
string[] versions = moduledefinition.ReleaseVersions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey))))
{
int index = Array.FindIndex(versions, item => item == moduledefinition.Version);
if (tenant.Name == install.TenantName && install.TenantName != Constants.MasterTenant)
foreach (var tenant in db.Tenant.ToList())
{
index = -1;
}
if (index != (versions.Length - 1))
{
if (index == -1) index = 0;
for (int i = index; i < versions.Length; i++)
int index = Array.FindIndex(versions, item => item == moduledefinition.Version);
if (tenant.Name == install.TenantName && install.TenantName != Constants.MasterTenant)
{
try
index = -1;
}
if (index != (versions.Length - 1))
{
if (index == -1) index = 0;
for (int i = index; i < versions.Length; i++)
{
if (moduletype.GetInterface("IInstallable") != null)
try
{
var moduleobject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduletype);
if (moduletype.GetInterface("IInstallable") != null)
{
var moduleobject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduletype);
((IInstallable)moduleobject).Install(tenant, versions[i]);
}
else
{
sql.ExecuteScript(tenant, moduletype.Assembly, Utilities.GetTypeName(moduledefinition.ModuleDefinitionName) + "." + versions[i] + ".sql");
}
}
else
catch (Exception ex)
{
sql.ExecuteScript(tenant, moduletype.Assembly, Utilities.GetTypeName(moduledefinition.ModuleDefinitionName) + "." + versions[i] + ".sql");
result.Message = "An Error Occurred Installing " + moduledefinition.Name + " Version " + versions[i] + " - " + ex.Message.ToString();
}
}
catch (Exception ex)
{
result.Message = "An Error Occurred Installing " + moduledefinition.Name + " Version " + versions[i] + " - " + ex.Message.ToString();
}
}
}
}
if (string.IsNullOrEmpty(result.Message) && moduledefinition.Version != versions[versions.Length - 1])
{
moduledefinition.Version = versions[versions.Length - 1];
db.Entry(moduledefinition).State = EntityState.Modified;
db.SaveChanges();
if (string.IsNullOrEmpty(result.Message) && moduledefinition.Version != versions[versions.Length - 1])
{
moduledefinition.Version = versions[versions.Length - 1];
db.Entry(moduledefinition).State = EntityState.Modified;
db.SaveChanges();
}
}
}
}
@ -461,7 +463,7 @@ namespace Oqtane.Infrastructure
userroles.AddUserRole(userRole);
// add user folder
var folder = folders.GetFolder(user.SiteId, Utilities.PathCombine("Users", "\\"));
var folder = folders.GetFolder(user.SiteId, Utilities.PathCombine("Users", Path.DirectorySeparatorChar.ToString()));
if (folder != null)
{
folders.AddFolder(new Folder
@ -469,7 +471,7 @@ namespace Oqtane.Infrastructure
SiteId = folder.SiteId,
ParentId = folder.FolderId,
Name = "My Folder",
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), "\\"),
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()),
Order = 1,
IsSystem = true,
Permissions = new List<Permission>

View File

@ -1,13 +1,15 @@
using System.Reflection;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Hosting;
using System.Reflection;
using System.Text.Json;
using System.Xml;
using Oqtane.Shared;
using System;
using System.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Hosting;
using Oqtane.Shared;
namespace Oqtane.Infrastructure
{
@ -27,7 +29,7 @@ namespace Oqtane.Infrastructure
public void InstallPackages(string folders, bool restart)
{
var webRootPath = _environment.WebRootPath;
var install = InstallPackages(folders, webRootPath);
if (install && restart)
@ -80,6 +82,8 @@ namespace Oqtane.Infrastructure
// if compatible with framework version
if (frameworkversion == "" || Version.Parse(Constants.Version).CompareTo(Version.Parse(frameworkversion)) >= 0)
{
List<string> assets = new List<string>();
// module and theme packages must be in form of name.1.0.0.nupkg
string name = Path.GetFileNameWithoutExtension(packagename);
string[] segments = name?.Split('.');
@ -88,7 +92,7 @@ namespace Oqtane.Infrastructure
// deploy to appropriate locations
foreach (ZipArchiveEntry entry in archive.Entries)
{
string foldername = Path.GetDirectoryName(entry.FullName).Split('\\')[0];
string foldername = Path.GetDirectoryName(entry.FullName).Split(Path.DirectorySeparatorChar)[0];
string filename = Path.GetFileName(entry.FullName);
switch (foldername)
@ -96,13 +100,32 @@ namespace Oqtane.Infrastructure
case "lib":
filename = Path.Combine(binFolder, filename);
ExtractFile(entry, filename);
assets.Add(filename);
break;
case "wwwroot":
filename = Path.Combine(webRootPath, Utilities.PathCombine(entry.FullName.Replace("wwwroot/", "").Split('/')));
filename = Path.Combine(webRootPath.Replace(Path.DirectorySeparatorChar + "wwwroot", ""), Utilities.PathCombine(entry.FullName.Split('/')));
ExtractFile(entry, filename);
assets.Add(filename);
break;
case "runtimes":
var destSubFolder = Path.GetDirectoryName(entry.FullName);
filename = Path.Combine(binFolder, destSubFolder, filename);
ExtractFile(entry, filename);
assets.Add(filename);
break;
}
}
// save list of assets
if (assets.Count != 0)
{
string assetfilepath = Path.Combine(webRootPath, "Modules", name, "assets.json");
if (File.Exists(assetfilepath))
{
File.Delete(assetfilepath);
}
File.WriteAllText(assetfilepath, JsonSerializer.Serialize(assets));
}
}
}
@ -121,7 +144,15 @@ namespace Oqtane.Infrastructure
{
Directory.CreateDirectory(Path.GetDirectoryName(filename));
}
entry.ExtractToFile(filename, true);
try
{
entry.ExtractToFile(filename, true);
}
catch
{
// an error occurred extracting the file
}
}
public void UpgradeFramework()
@ -131,7 +162,7 @@ namespace Oqtane.Infrastructure
{
// get package with highest version and clean up any others
string packagename = "";
foreach(string package in Directory.GetFiles(folder, "Oqtane.Framework.*.nupkg"))
foreach (string package in Directory.GetFiles(folder, "Oqtane.Framework.*.nupkg"))
{
if (packagename != "")
{
@ -163,12 +194,13 @@ namespace Oqtane.Infrastructure
packageversion = node.InnerText;
}
reader.Close();
break;
}
}
}
// ensure package version is higher than current framework version
if (packageversion != "" && Version.Parse(Constants.Version).CompareTo(Version.Parse(packageversion)) < 0)
// ensure package version is greater than or equal to current framework version
if (packageversion != "" && Version.Parse(Constants.Version).CompareTo(Version.Parse(packageversion)) <= 0)
{
FinishUpgrade();
}
@ -179,28 +211,26 @@ namespace Oqtane.Infrastructure
private void FinishUpgrade()
{
// check if upgrade application exists
string Upgrader = "Oqtane.Upgrade.dll";
string folder = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
if (folder == null || !File.Exists(Path.Combine(folder, "Oqtane.Upgrade.exe"))) return;
if (folder == null || !File.Exists(Path.Combine(folder, Upgrader))) return;
// run upgrade application
var process = new Process
using (var process = new Process())
{
StartInfo =
process.StartInfo = new ProcessStartInfo
{
FileName = Path.Combine(folder, "Oqtane.Upgrade.exe"),
Arguments = "\"" + _environment.ContentRootPath + "\" \"" + _environment.WebRootPath + "\"",
ErrorDialog = false,
WorkingDirectory = folder,
FileName = "dotnet",
Arguments = Path.Combine(folder, Upgrader) + " \"" + _environment.ContentRootPath + "\" \"" + _environment.WebRootPath + "\"",
UseShellExecute = false,
ErrorDialog = false,
CreateNoWindow = true,
RedirectStandardOutput = false,
RedirectStandardError = false
}
};
process.Start();
};
process.Start();
process.Dispose();
// stop application so upgrade application can proceed
RestartApplication();
}
public void RestartApplication()

View File

@ -0,0 +1,11 @@
using Oqtane.Models;
using System.Collections.Generic;
namespace Oqtane.Infrastructure
{
public interface IHostResources
{
List<Resource> Resources { get; } // identifies global resources for an application
}
}

View File

@ -27,8 +27,10 @@ namespace Oqtane.Infrastructure
protected async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Yield(); // required so that this method does not block startup
try
{
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _serviceScopeFactory.CreateScope())
@ -41,21 +43,26 @@ namespace Oqtane.Infrastructure
Job job = jobs.GetJobs().Where(item => item.JobType == jobType).FirstOrDefault();
if (job != null && job.IsEnabled && !job.IsExecuting)
{
// set next execution date
// get next execution date
DateTime NextExecution;
if (job.NextExecution == null)
{
if (job.StartDate != null)
{
job.NextExecution = job.StartDate;
NextExecution = job.StartDate.Value;
}
else
{
job.NextExecution = DateTime.UtcNow;
NextExecution = DateTime.UtcNow;
}
}
else
{
NextExecution = job.NextExecution.Value;
}
// determine if the job should be run
if (job.NextExecution <= DateTime.UtcNow && (job.EndDate == null || job.EndDate >= DateTime.UtcNow))
if (NextExecution <= DateTime.UtcNow && (job.EndDate == null || job.EndDate >= DateTime.UtcNow))
{
IJobLogRepository jobLogs = scope.ServiceProvider.GetRequiredService<IJobLogRepository>();
@ -89,7 +96,7 @@ namespace Oqtane.Infrastructure
jobLogs.UpdateJobLog(log);
// update the job
job.NextExecution = CalculateNextExecution(job.NextExecution.Value, job.Frequency, job.Interval);
job.NextExecution = CalculateNextExecution(NextExecution, job.Frequency, job.Interval);
job.IsExecuting = false;
jobs.UpdateJob(job);

View File

@ -20,11 +20,15 @@ namespace Oqtane.Infrastructure
{
string log = "";
// iterate through aliases in this installation
// iterate through tenants in this installation
List<int> tenants = new List<int>();
var aliasRepository = provider.GetRequiredService<IAliasRepository>();
List<Alias> aliases = aliasRepository.GetAliases().ToList();
foreach (Alias alias in aliases)
{
if (tenants.Contains(alias.TenantId)) continue;
tenants.Add(alias.TenantId);
// use the SiteState to set the Alias explicitly so the tenant can be resolved
var siteState = provider.GetRequiredService<SiteState>();
siteState.Alias = alias;
@ -34,11 +38,11 @@ namespace Oqtane.Infrastructure
var settingRepository = provider.GetRequiredService<ISettingRepository>();
var notificationRepository = provider.GetRequiredService<INotificationRepository>();
// iterate through sites
// iterate through sites for this tenant
List<Site> sites = siteRepository.GetSites().ToList();
foreach (Site site in sites)
{
log += "Processing Notifications For Site: " + site.Name + "\n\n";
log += "Processing Notifications For Site: " + site.Name + "<br />";
// get site settings
List<Setting> sitesettings = settingRepository.GetSettings(EntityNames.Site, site.SiteId).ToList();
@ -101,14 +105,14 @@ namespace Oqtane.Infrastructure
catch (Exception ex)
{
// error
log += ex.Message + "\n\n";
log += ex.Message + "<br />";
}
}
log += "Notifications Delivered: " + sent + "\n\n";
log += "Notifications Delivered: " + sent + "<br />";
}
else
{
log += "SMTP Not Configured" + "\n\n";
log += "SMTP Not Configured" + "<br />";
}
}
}
@ -116,7 +120,6 @@ namespace Oqtane.Infrastructure
return log;
}
private Dictionary<string, string> GetSettings(List<Setting> settings)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();

View File

@ -42,7 +42,6 @@ namespace Oqtane.SiteTemplates
Icon = "home",
IsNavigation = true,
IsPersonalizable = false,
EditMode = false,
PagePermissions = new List<Permission> {
new Permission(PermissionNames.View, Constants.AllUsersRole, true),
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -89,7 +88,6 @@ namespace Oqtane.SiteTemplates
Icon = "lock-locked",
IsNavigation = true,
IsPersonalizable = false,
EditMode = false,
PagePermissions = new List<Permission> {
new Permission(PermissionNames.View, Constants.RegisteredRole, true),
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -114,7 +112,6 @@ namespace Oqtane.SiteTemplates
Icon = "target",
IsNavigation = true,
IsPersonalizable = true,
EditMode = false,
PagePermissions = new List<Permission> {
new Permission(PermissionNames.View, Constants.AllUsersRole, true),
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -134,7 +131,7 @@ namespace Oqtane.SiteTemplates
if (System.IO.File.Exists(Path.Combine(_environment.WebRootPath, "images", "logo-white.png")))
{
string folderpath = Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", site.TenantId.ToString(), "Sites", site.SiteId.ToString(),"\\");
string folderpath = Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", site.TenantId.ToString(), "Sites", site.SiteId.ToString(), Path.DirectorySeparatorChar.ToString());
System.IO.Directory.CreateDirectory(folderpath);
if (!System.IO.File.Exists(Path.Combine(folderpath, "logo-white.png")))
{

View File

@ -30,7 +30,6 @@ namespace Oqtane.SiteTemplates
Icon = "home",
IsNavigation = true,
IsPersonalizable = false,
EditMode = false,
PagePermissions = new List<Permission> {
new Permission(PermissionNames.View, Constants.AllUsersRole, true),
new Permission(PermissionNames.View, Constants.AdminRole, true),

View File

@ -8,24 +8,18 @@ using System;
using System.Collections.Generic;
using Oqtane.Enums;
using Oqtane.Infrastructure;
using Oqtane.Controllers;
namespace Oqtane.Modules.HtmlText.Controllers
{
[Route("{alias}/api/[controller]")]
public class HtmlTextController : Controller
public class HtmlTextController : ModuleControllerBase
{
private readonly IHtmlTextRepository _htmlText;
private readonly ILogManager _logger;
private int _entityId = -1; // passed as a querystring parameter for authorization and used for validation
public HtmlTextController(IHtmlTextRepository htmlText, ILogManager logger, IHttpContextAccessor httpContextAccessor)
public HtmlTextController(IHtmlTextRepository htmlText, ILogManager logger, IHttpContextAccessor accessor) : base(logger, accessor)
{
_htmlText = htmlText;
_logger = logger;
if (httpContextAccessor.HttpContext.Request.Query.ContainsKey("entityid"))
{
_entityId = int.Parse(httpContextAccessor.HttpContext.Request.Query["entityid"]);
}
}
// GET api/<controller>/5

View File

@ -4,7 +4,7 @@
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>7.3</LangVersion>
<Configurations>Debug;Release</Configurations>
<Version>1.0.1</Version>
<Version>1.0.4</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -13,7 +13,7 @@
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<RepositoryUrl>https://github.com/oqtane</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.1</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.4</PackageReleaseNotes>
<RootNamespace>Oqtane</RootNamespace>
<IsPackable>true</IsPackable>
</PropertyGroup>
@ -32,6 +32,7 @@
<EmbeddedResource Include="Scripts\Tenant.00.09.02.00.sql" />
<EmbeddedResource Include="Scripts\Tenant.01.00.01.00.sql" />
<EmbeddedResource Include="Scripts\Tenant.01.00.01.01.sql" />
<EmbeddedResource Include="Scripts\Tenant.01.00.02.01.sql" />
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.1.0.0.sql" />
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.Uninstall.sql" />
</ItemGroup>
@ -48,5 +49,16 @@
<ItemGroup>
<ProjectReference Include="..\Oqtane.Client\Oqtane.Client.csproj" />
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
<ProjectReference Include="..\Oqtane.Upgrade\Oqtane.Upgrade.csproj" />
</ItemGroup>
</Project>
<ItemGroup>
<UpgradeFiles Include="$(ProjectDir)bin\Release\netcoreapp3.1\Oqtane.Upgrade.deps.json" />
<UpgradeFiles Include="$(ProjectDir)bin\Release\netcoreapp3.1\Oqtane.Upgrade.dll" />
<UpgradeFiles Include="$(ProjectDir)bin\Release\netcoreapp3.1\Oqtane.Upgrade.pdb" />
<UpgradeFiles Include="$(ProjectDir)bin\Release\netcoreapp3.1\Oqtane.Upgrade.runtimeconfig.json" />
<TemplateFiles Include="$(ProjectDir)wwwroot\Modules\Templates\**\*.*" />
</ItemGroup>
<Target Name="AddPayloadsFolder" AfterTargets="Publish">
<Copy SourceFiles="@(UpgradeFiles)" DestinationFiles="@(UpgradeFiles->'$(PublishDir)%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
<Copy SourceFiles="@(TemplateFiles)" DestinationFiles="@(TemplateFiles->'$(PublishDir)wwwroot\Modules\Templates\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
</Target></Project>

View File

@ -3,6 +3,7 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@model Oqtane.Pages.HostModel
<!DOCTYPE html>
<html>
@ -16,6 +17,7 @@
<link id="app-manifest" rel="manifest" />
<link rel="stylesheet" href="css/app.css" />
<script src="js/loadjs.min.js"></script>
@Html.Raw(@Model.Resources)
</head>
<body>
@(Html.AntiForgeryToken())
@ -30,7 +32,7 @@
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="~/" class="reload">Reload</a>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>

View File

@ -0,0 +1,62 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
using Oqtane.Infrastructure;
using Oqtane.Shared;
using System;
using System.Linq;
using System.Reflection;
namespace Oqtane.Pages
{
public class HostModel : PageModel
{
public string Resources = "";
public void OnGet()
{
var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies();
foreach (Assembly assembly in assemblies)
{
var types = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IHostResources)));
foreach (var type in types)
{
var obj = Activator.CreateInstance(type) as IHostResources;
foreach (var resource in obj.Resources)
{
switch (resource.ResourceType)
{
case ResourceType.Stylesheet:
Resources += "<link rel=\"stylesheet\" href=\"" + resource.Url + "\"" + CrossOrigin(resource.CrossOrigin) + Integrity(resource.Integrity) + " />" + Environment.NewLine;
break;
case ResourceType.Script:
Resources += "<script src=\"" + resource.Url + "\"" + CrossOrigin(resource.CrossOrigin) + Integrity(resource.Integrity) + "></script>" + Environment.NewLine;
break;
}
}
}
}
}
private string CrossOrigin(string crossorigin)
{
if (!string.IsNullOrEmpty(crossorigin))
{
return " crossorigin=\"" + crossorigin + "\"";
}
else
{
return "";
}
}
private string Integrity(string integrity)
{
if (!string.IsNullOrEmpty(integrity))
{
return " integrity=\"" + integrity + "\"";
}
else
{
return "";
}
}
}
}

View File

@ -45,7 +45,21 @@ namespace Oqtane.Repository
public File GetFile(int fileId)
{
File file = _db.File.Where(item => item.FileId == fileId).Include(item => item.Folder).FirstOrDefault();
return GetFile(fileId, true);
}
public File GetFile(int fileId, bool tracking)
{
File file;
if (tracking)
{
file = _db.File.Where(item => item.FileId == fileId).Include(item => item.Folder).FirstOrDefault();
}
else
{
file = _db.File.AsNoTracking().Where(item => item.FileId == fileId).Include(item => item.Folder).FirstOrDefault();
}
if (file != null)
{
IEnumerable<Permission> permissions = _permissions.GetPermissions(EntityNames.Folder, file.FolderId).ToList();

View File

@ -47,7 +47,20 @@ namespace Oqtane.Repository
public Folder GetFolder(int folderId)
{
Folder folder = _db.Folder.Find(folderId);
return GetFolder(folderId, true);
}
public Folder GetFolder(int folderId, bool tracking)
{
Folder folder;
if (tracking)
{
folder = _db.Folder.Where(item => item.FolderId == folderId).FirstOrDefault();
}
else
{
folder = _db.Folder.AsNoTracking().Where(item => item.FolderId == folderId).FirstOrDefault();
}
if (folder != null)
{
folder.Permissions = _permissions.GetPermissionString(EntityNames.Folder, folder.FolderId);

View File

@ -9,6 +9,7 @@ namespace Oqtane.Repository
File AddFile(File file);
File UpdateFile(File file);
File GetFile(int fileId);
File GetFile(int fileId, bool tracking);
void DeleteFile(int fileId);
}
}

View File

@ -9,6 +9,7 @@ namespace Oqtane.Repository
Folder AddFolder(Folder folder);
Folder UpdateFolder(Folder folder);
Folder GetFolder(int folderId);
Folder GetFolder(int folderId, bool tracking);
Folder GetFolder(int siteId, string path);
void DeleteFolder(int folderId);
}

View File

@ -123,7 +123,7 @@ namespace Oqtane.Repository
ModuleDefinition moduledefinition = moduledefinitions.Where(item => item.ModuleDefinitionName == module.ModuleDefinitionName).FirstOrDefault();
if (moduledefinition != null)
{
ModuleContent modulecontent = JsonSerializer.Deserialize<ModuleContent>(content);
ModuleContent modulecontent = JsonSerializer.Deserialize<ModuleContent>(content.Replace("\n", ""));
if (modulecontent.ModuleDefinitionName == moduledefinition.ModuleDefinitionName)
{
if (moduledefinition.ServerManagerType != "")
@ -147,9 +147,10 @@ namespace Oqtane.Repository
}
}
}
catch
catch (Exception ex)
{
// error occurred during import
string error = ex.Message;
}
return success;

View File

@ -21,7 +21,7 @@ namespace Oqtane.Repository
return _db.Notification
.Where(item => item.SiteId == siteId)
.Where(item => item.IsDelivered == false)
.Where(item => item.SendOn < System.DateTime.UtcNow)
.Where(item => item.SendOn == null || item.SendOn < System.DateTime.UtcNow)
.ToList();
}

View File

@ -58,7 +58,6 @@ namespace Oqtane.Repository
Icon = Icons.LockLocked,
IsNavigation = false,
IsPersonalizable = false,
EditMode = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -88,7 +87,6 @@ namespace Oqtane.Repository
Icon = Icons.Person,
IsNavigation = false,
IsPersonalizable = false,
EditMode = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -119,7 +117,6 @@ namespace Oqtane.Repository
Icon = Icons.Person,
IsNavigation = false,
IsPersonalizable = false,
EditMode = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -149,7 +146,6 @@ namespace Oqtane.Repository
Icon = Icons.Person,
IsNavigation = false,
IsPersonalizable = false,
EditMode = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -175,7 +171,7 @@ namespace Oqtane.Repository
// admin pages
pageTemplates.Add(new PageTemplate
{
Name = "Admin", Parent = "", Path = "admin", Icon = "", IsNavigation = false, IsPersonalizable = false, EditMode = true,
Name = "Admin", Parent = "", Path = "admin", Icon = "", IsNavigation = false, IsPersonalizable = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -203,7 +199,6 @@ namespace Oqtane.Repository
Icon = Icons.Home,
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -231,7 +226,6 @@ namespace Oqtane.Repository
Icon = Icons.Layers,
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -259,7 +253,6 @@ namespace Oqtane.Repository
Icon = Icons.People,
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -287,7 +280,6 @@ namespace Oqtane.Repository
Icon = Icons.Person,
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -315,7 +307,6 @@ namespace Oqtane.Repository
Icon = Icons.LockLocked,
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -343,7 +334,6 @@ namespace Oqtane.Repository
Icon = Icons.File,
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -371,7 +361,6 @@ namespace Oqtane.Repository
Icon = Icons.Trash,
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.AdminRole, true),
@ -401,7 +390,6 @@ namespace Oqtane.Repository
Icon = Icons.MagnifyingGlass,
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.HostRole, true),
@ -428,7 +416,6 @@ namespace Oqtane.Repository
Icon = Icons.List,
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.HostRole, true),
@ -450,7 +437,7 @@ namespace Oqtane.Repository
});
pageTemplates.Add(new PageTemplate
{
Name = "Site Management", Parent = "Admin", Path = "admin/sites", Icon = Icons.Globe, IsNavigation = false, IsPersonalizable = false, EditMode = true,
Name = "Site Management", Parent = "Admin", Path = "admin/sites", Icon = Icons.Globe, IsNavigation = false, IsPersonalizable = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.HostRole, true),
@ -472,7 +459,7 @@ namespace Oqtane.Repository
});
pageTemplates.Add(new PageTemplate
{
Name = "Module Management", Parent = "Admin", Path = "admin/modules", Icon = Icons.Browser, IsNavigation = false, IsPersonalizable = false, EditMode = true,
Name = "Module Management", Parent = "Admin", Path = "admin/modules", Icon = Icons.Browser, IsNavigation = false, IsPersonalizable = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.HostRole, true),
@ -494,7 +481,7 @@ namespace Oqtane.Repository
});
pageTemplates.Add(new PageTemplate
{
Name = "Theme Management", Parent = "Admin", Path = "admin/themes", Icon = Icons.Brush, IsNavigation = false, IsPersonalizable = false, EditMode = true,
Name = "Theme Management", Parent = "Admin", Path = "admin/themes", Icon = Icons.Brush, IsNavigation = false, IsPersonalizable = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.HostRole, true),
@ -516,7 +503,7 @@ namespace Oqtane.Repository
});
pageTemplates.Add(new PageTemplate
{
Name = "Scheduled Jobs", Parent = "Admin", Path = "admin/jobs", Icon = Icons.Timer, IsNavigation = false, IsPersonalizable = false, EditMode = true,
Name = "Scheduled Jobs", Parent = "Admin", Path = "admin/jobs", Icon = Icons.Timer, IsNavigation = false, IsPersonalizable = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.HostRole, true),
@ -544,7 +531,6 @@ namespace Oqtane.Repository
Icon = "spreadsheet",
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.HostRole, true),
@ -572,7 +558,6 @@ namespace Oqtane.Repository
Icon = "medical-cross",
IsNavigation = false,
IsPersonalizable = false,
EditMode = true,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.HostRole, true),
@ -594,7 +579,7 @@ namespace Oqtane.Repository
});
pageTemplates.Add(new PageTemplate
{
Name = "System Update", Parent = "Admin", Path = "admin/update", Icon = Icons.Aperture, IsNavigation = false, IsPersonalizable = false, EditMode = true,
Name = "System Update", Parent = "Admin", Path = "admin/update", Icon = Icons.Aperture, IsNavigation = false, IsPersonalizable = false,
PagePermissions = new List<Permission>
{
new Permission(PermissionNames.View, Constants.HostRole, true),
@ -692,7 +677,7 @@ namespace Oqtane.Repository
});
_folderRepository.AddFolder(new Folder
{
SiteId = site.SiteId, ParentId = folder.FolderId, Name = "Users", Path = Utilities.PathCombine("Users","\\"), Order = 1, IsSystem = true,
SiteId = site.SiteId, ParentId = folder.FolderId, Name = "Users", Path = Utilities.PathCombine("Users",Path.DirectorySeparatorChar.ToString()), Order = 1, IsSystem = true,
Permissions = "[{\"PermissionName\":\"Browse\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]"
});
@ -754,7 +739,6 @@ namespace Oqtane.Repository
Order = 1,
Url = "",
IsNavigation = pagetemplate.IsNavigation,
EditMode = pagetemplate.EditMode,
ThemeType = "",
LayoutType = "",
DefaultContainerType = "",

View File

@ -0,0 +1,9 @@
/*
Version 1.0.2.1 migration script
*/
ALTER TABLE [dbo].[Page]
DROP COLUMN EditMode
GO

View File

@ -0,0 +1,3 @@
ALTER TABLE [dbo].[Page]
ALTER COLUMN [Path] [nvarchar](256) NOT NULL
GO

View File

@ -72,7 +72,7 @@ namespace Oqtane
});
}
// register authorization services
// register custom authorization policies
services.AddAuthorizationCore(options =>
{
options.AddPolicy("ViewPage", policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Page, PermissionNames.View)));

View File

@ -0,0 +1,15 @@
{
"Runtime": "Server",
"ConnectionStrings": {
"DefaultConnection": ""
},
"Installation": {
"DefaultAlias": "",
"HostPassword": "",
"HostEmail": "",
"SiteTemplate": "",
"DefaultTheme": "",
"DefaultLayout": "",
"DefaultContainer": ""
}
}

View File

@ -1,8 +1,8 @@
@using Oqtane.Modules.Controls
@using [Owner].[Module]s.Services
@using [Owner].[Module]s.Models
@using [Owner].[Module].Services
@using [Owner].[Module].Models
@namespace [Owner].[Module]s
@namespace [Owner].[Module]
@inherits ModuleBase
@inject I[Module]Service [Module]Service
@inject NavigationManager NavigationManager
@ -10,10 +10,10 @@
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
<Label For="name" HelpText="Enter a name">Name: </Label>
</td>
<td>
<input id="_name" class="form-control" @bind="@_name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
</table>
@ -31,6 +31,8 @@
public override string Actions => "Add,Edit";
public override string Title => "Manage [Module]";
public override List<Resource> Resources => new List<Resource>()
{
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
@ -50,7 +52,7 @@
if (PageState.Action == "Edit")
{
_id = Int32.Parse(PageState.QueryString["id"]);
[Module] [Module] = await [Module]Service.Get[Module]Async(_id);
[Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
if ([Module] != null)
{
_name = [Module].Name;
@ -82,7 +84,7 @@
}
else
{
[Module] [Module] = await [Module]Service.Get[Module]Async(_id);
[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]);

View File

@ -1,7 +1,7 @@
@using [Owner].[Module]s.Services
@using [Owner].[Module]s.Models
@using [Owner].[Module].Services
@using [Owner].[Module].Models
@namespace [Owner].[Module]s
@namespace [Owner].[Module]
@inherits ModuleBase
@inject I[Module]Service [Module]Service
@inject NavigationManager NavigationManager
@ -17,16 +17,16 @@ else
<br />
@if (@_[Module]s.Count != 0)
{
<Pager Items="@_[Module]s" Format="Grid">
<Pager Items="@_[Module]s">
<Header>
<div class="col"><strong>[Module]s</strong></div>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<div class="col">
<ActionLink Action="Edit" Parameters="@($"id=" + context.[Module]Id.ToString())" />
<ActionDialog Header="Delete [Module]" Message="@("Are You Sure You Wish To Delete The " + context.Name + " [Module]?")" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" />
@context.Name
</div>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.[Module]Id.ToString())" /></td>
<td><ActionDialog Header="Delete [Module]" Message="@("Are You Sure You Wish To Delete The " + context.Name + " [Module]?")" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" /></td>
<td>@context.Name</td>
</Row>
</Pager>
}
@ -41,7 +41,7 @@ else
<hr />
[Module] Module Created Successfully. Use Edit Mode To Add A [Module]. You Can Access The Files At The Following Locations:<br /><br />
[RootPath]Client\<br />
- [Owner].[Module]s.Client.csproj - client project<br />
- [Owner].[Module].Client.csproj - client project<br />
- _Imports.razor - global imports for module components<br />
- Edit.razor - component for adding or editing content<br />
- Index.razor - main component for your module **the content you are reading is in this file**<br />
@ -50,22 +50,22 @@ else
- Services\I[Module]Service.cs - interface for defining service API methods<br />
- Services\[Module]Service.cs - implements service API interface methods<br /><br />
[RootPath]Package\<br />
- [Owner].[Module]s.nuspec - nuget manifest for packaging module<br />
- [Owner].[Module]s.Package.csproj - packaging project<br />
- [Owner].[Module].nuspec - nuget manifest for packaging module<br />
- [Owner].[Module].Package.csproj - packaging project<br />
- debug.cmd - copies assemblies to Oqtane bin folder when in Debug mode<br />
- release.cmd - creates nuget package and deploys to Oqtane wwwroot/modules folder when in Release mode<br /><br />
[RootPath]Server\<br />
- [Owner].[Module]s.Server.csproj - server project<br />
- [Owner].[Module].Server.csproj - server project<br />
- Controllers\[Module]Controller.cs - API methods implemented using a REST pattern<br />
- Manager\[Module]Manager.cs - implements optional module interfaces for features such as import/export of content<br />
- Repository\I[Module]Repository.cs - interface for defining repository methods<br />
- Repository\[Module]Respository.cs - implements repository interface methods for data access using EF Core<br />
- Repository\[Module]Context.cs - provides a DB Context for data access<br />
- Scripts\[Owner].[Module]s.1.0.0.sql - database schema definition script<br />
- Scripts\[Owner].[Module]s.Uninstall.sql - database uninstall script<br />
- Scripts\[Owner].[Module].1.0.0.sql - database schema definition script<br />
- Scripts\[Owner].[Module].Uninstall.sql - database uninstall script<br />
- wwwroot\Module.css - module style sheet<br /><br />
[RootPath]Shared\<br />
- [Owner].[Module]s.csproj - shared project<br />
- [Owner].[Module].csproj - shared project<br />
- Models\[Module].cs - model definition<br /><br />
<!-- The content above is for informational purposes only and can be safely removed -->
@ -73,7 +73,8 @@ else
@code {
public override List<Resource> Resources => new List<Resource>()
{
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
new Resource { ResourceType = ResourceType.Script, Url = ModulePath() + "Module.js" }
};
List<[Module]> _[Module]s;
@ -95,7 +96,7 @@ else
{
try
{
await [Module]Service.Delete[Module]Async([Module].[Module]Id);
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);
StateHasChanged();

View File

@ -0,0 +1,15 @@
using Microsoft.JSInterop;
using System.Threading.Tasks;
namespace [Owner].[Module]
{
public class Interop
{
private readonly IJSRuntime _jsRuntime;
public Interop(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
}
}

View File

@ -1,7 +1,7 @@
using Oqtane.Models;
using Oqtane.Modules;
namespace [Owner].[Module]s
namespace [Owner].[Module]
{
public class ModuleInfo : IModule
{
@ -12,7 +12,7 @@ namespace [Owner].[Module]s
Version = "1.0.0",
ServerManagerType = "[ServerManagerType]",
ReleaseVersions = "1.0.0",
Dependencies = "[Owner].[Module]s.Shared.Oqtane"
Dependencies = "[Owner].[Module].Shared.Oqtane"
};
}
}

View File

@ -1,19 +1,19 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using [Owner].[Module]s.Models;
using [Owner].[Module].Models;
namespace [Owner].[Module]s.Services
namespace [Owner].[Module].Services
{
public interface I[Module]Service
{
Task<List<[Module]>> Get[Module]sAsync(int ModuleId);
Task<List<Models.[Module]>> Get[Module]sAsync(int ModuleId);
Task<[Module]> Get[Module]Async(int [Module]Id);
Task<Models.[Module]> Get[Module]Async(int [Module]Id, int ModuleId);
Task<[Module]> Add[Module]Async([Module] [Module]);
Task<Models.[Module]> Add[Module]Async(Models.[Module] [Module]);
Task<[Module]> Update[Module]Async([Module] [Module]);
Task<Models.[Module]> Update[Module]Async(Models.[Module] [Module]);
Task Delete[Module]Async(int [Module]Id);
Task Delete[Module]Async(int [Module]Id, int ModuleId);
}
}

View File

@ -5,9 +5,9 @@ using System.Threading.Tasks;
using Oqtane.Modules;
using Oqtane.Services;
using Oqtane.Shared;
using [Owner].[Module]s.Models;
using [Owner].[Module].Models;
namespace [Owner].[Module]s.Services
namespace [Owner].[Module].Services
{
public class [Module]Service : ServiceBase, I[Module]Service, IService
{
@ -18,32 +18,32 @@ namespace [Owner].[Module]s.Services
_siteState = siteState;
}
private string Apiurl=> CreateApiUrl(_siteState.Alias, "[Module]");
private string Apiurl => CreateApiUrl(_siteState.Alias, "[Module]");
public async Task<List<[Module]>> Get[Module]sAsync(int ModuleId)
public async Task<List<Models.[Module]>> Get[Module]sAsync(int ModuleId)
{
List<[Module]> [Module]s = await GetJsonAsync<List<[Module]>>($"{Apiurl}?moduleid={ModuleId}");
List<Models.[Module]> [Module]s = await GetJsonAsync<List<Models.[Module]>>(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", ModuleId));
return [Module]s.OrderBy(item => item.Name).ToList();
}
public async Task<[Module]> Get[Module]Async(int [Module]Id)
public async Task<Models.[Module]> Get[Module]Async(int [Module]Id, int ModuleId)
{
return await GetJsonAsync<[Module]>($"{Apiurl}/{[Module]Id}");
return await GetJsonAsync<Models.[Module]>(CreateAuthorizationPolicyUrl($"{Apiurl}/{[Module]Id}", ModuleId));
}
public async Task<[Module]> Add[Module]Async([Module] [Module])
public async Task<Models.[Module]> Add[Module]Async(Models.[Module] [Module])
{
return await PostJsonAsync<[Module]>($"{Apiurl}?entityid={[Module].ModuleId}", [Module]);
return await PostJsonAsync<Models.[Module]>(CreateAuthorizationPolicyUrl($"{Apiurl}", [Module].ModuleId), [Module]);
}
public async Task<[Module]> Update[Module]Async([Module] [Module])
public async Task<Models.[Module]> Update[Module]Async(Models.[Module] [Module])
{
return await PutJsonAsync<[Module]>($"{Apiurl}/{[Module].[Module]Id}?entityid={[Module].ModuleId}", [Module]);
return await PutJsonAsync<Models.[Module]>(CreateAuthorizationPolicyUrl($"{Apiurl}/{[Module].[Module]Id}", [Module].ModuleId), [Module]);
}
public async Task Delete[Module]Async(int [Module]Id)
public async Task Delete[Module]Async(int [Module]Id, int ModuleId)
{
await DeleteAsync($"{Apiurl}/{[Module]Id}");
await DeleteAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{[Module]Id}", ModuleId));
}
}
}

View File

@ -1,14 +1,14 @@
@namespace [Owner].[Module]s
@namespace [Owner].[Module]
@inherits ModuleBase
@inject ISettingService SettingService
<table class="table table-borderless">
<tr>
<td>
<label for="Setting" class="control-label">Setting: </label>
<Label For="value" HelpText="Enter a value">Name: </Label>
</td>
<td>
<input type="text" class="form-control" @bind="_value" />
<input id="value" type="text" class="form-control" @bind="@_value" />
</td>
</tr>
</table>

View File

@ -7,9 +7,9 @@
<Authors>[Owner]</Authors>
<Company>[Owner]</Company>
<Description>[Description]</Description>
<Product>[Owner].[Module]s</Product>
<Product>[Owner].[Module]</Product>
<Copyright>[Owner]</Copyright>
<AssemblyName>[Owner].[Module]s.Client.Oqtane</AssemblyName>
<AssemblyName>[Owner].[Module].Client.Oqtane</AssemblyName>
</PropertyGroup>
<ItemGroup>
@ -21,12 +21,12 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\[Owner].[Module]s.Shared.csproj" />
<ProjectReference Include="..\Shared\[Owner].[Module].Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Oqtane.Client" Version="1.0.1" />
<PackageReference Include="Oqtane.Shared" Version="1.0.1" />
[ClientReference]
[SharedReference]
</ItemGroup>
<PropertyGroup>

View File

@ -6,9 +6,9 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Client\[Owner].[Module]s.Client.csproj" />
<ProjectReference Include="..\Server\[Owner].[Module]s.Server.csproj" />
<ProjectReference Include="..\Shared\[Owner].[Module]s.Shared.csproj" />
<ProjectReference Include="..\Client\[Owner].[Module].Client.csproj" />
<ProjectReference Include="..\Server\[Owner].[Module].Server.csproj" />
<ProjectReference Include="..\Shared\[Owner].[Module].Shared.csproj" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>[Owner].[Module]s</id>
<id>[Owner].[Module]</id>
<version>1.0.0</version>
<authors>[Owner]</authors>
<owners>[Owner]</owners>
<title>[Module]s</title>
<description>[Module]s</description>
<title>[Module]</title>
<description>[Module]</description>
<copyright>[Owner]</copyright>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license>
@ -20,12 +20,12 @@
</dependencies>
</metadata>
<files>
<file src="..\Client\bin\Release\netstandard2.1\[Owner].[Module]s.Client.Oqtane.dll" target="lib\netstandard2.1" />
<file src="..\Client\bin\Release\netstandard2.1\[Owner].[Module]s.Client.Oqtane.pdb" target="lib\netstandard2.1" />
<file src="..\Server\bin\Release\netcoreapp3.1\[Owner].[Module]s.Server.Oqtane.dll" target="lib\netcoreapp3.1" />
<file src="..\Server\bin\Release\netcoreapp3.1\[Owner].[Module]s.Server.Oqtane.pdb" target="lib\netcoreapp3.1" />
<file src="..\Shared\bin\Release\netstandard2.1\[Owner].[Module]s.Shared.Oqtane.dll" target="lib\netstandard2.1" />
<file src="..\Shared\bin\Release\netstandard2.1\[Owner].[Module]s.Shared.Oqtane.pdb" target="lib\netstandard2.1" />
<file src="..\Client\bin\Release\netstandard2.1\[Owner].[Module].Client.Oqtane.dll" target="lib\netstandard2.1" />
<file src="..\Client\bin\Release\netstandard2.1\[Owner].[Module].Client.Oqtane.pdb" target="lib\netstandard2.1" />
<file src="..\Server\bin\Release\netcoreapp3.1\[Owner].[Module].Server.Oqtane.dll" target="lib\netcoreapp3.1" />
<file src="..\Server\bin\Release\netcoreapp3.1\[Owner].[Module].Server.Oqtane.pdb" target="lib\netcoreapp3.1" />
<file src="..\Shared\bin\Release\netstandard2.1\[Owner].[Module].Shared.Oqtane.dll" target="lib\netstandard2.1" />
<file src="..\Shared\bin\Release\netstandard2.1\[Owner].[Module].Shared.Oqtane.pdb" target="lib\netstandard2.1" />
<file src="..\Server\wwwroot\**\*.*" target="wwwroot" />
</files>
</package>

View File

@ -1,7 +1,7 @@
XCOPY "..\Client\bin\Debug\netstandard2.1\[Owner].[Module]s.Client.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Client\bin\Debug\netstandard2.1\[Owner].[Module]s.Client.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Server\bin\Debug\netcoreapp3.1\[Owner].[Module]s.Server.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Server\bin\Debug\netcoreapp3.1\[Owner].[Module]s.Server.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Shared\bin\Debug\netstandard2.1\[Owner].[Module]s.Shared.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Shared\bin\Debug\netstandard2.1\[Owner].[Module]s.Shared.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Server\wwwroot\Modules\[Owner].[Module]s\*" "..\..\[RootFolder]\Oqtane.Server\wwwroot\Modules\[Owner].[Module]s\" /Y /S /I
XCOPY "..\Client\bin\Debug\netstandard2.1\[Owner].[Module].Client.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Client\bin\Debug\netstandard2.1\[Owner].[Module].Client.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Server\bin\Debug\netcoreapp3.1\[Owner].[Module].Server.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Server\bin\Debug\netcoreapp3.1\[Owner].[Module].Server.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Shared\bin\Debug\netstandard2.1\[Owner].[Module].Shared.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Shared\bin\Debug\netstandard2.1\[Owner].[Module].Shared.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\netcoreapp3.1\" /Y
XCOPY "..\Server\wwwroot\Modules\[Owner].[Module]\*" "..\..\[RootFolder]\Oqtane.Server\wwwroot\Modules\[Owner].[Module]\" /Y /S /I

Some files were not shown because too many files have changed in this diff Show More