Compare commits

..

532 Commits

Author SHA1 Message Date
9ea5da525b Merge pull request #634 from sbwalker/master
preparing for 1.0.1 release
2020-06-23 09:42:25 -04:00
fa15a5e44b preparing for 1.0.1 release 2020-06-23 09:41:17 -04:00
35d037bbf4 Merge pull request #40 from oqtane/master
sync
2020-06-23 09:13:58 -04:00
e8387103f1 Merge pull request #631 from svreic/bugfix/fixing-theme-service
Fixed ThemeService using tenant aware api calls
2020-06-22 16:59:54 -04:00
16965fd027 Merge pull request #632 from sbwalker/master
enhancement to load dependencies from the /bin if they are not loaded automatically
2020-06-22 16:59:43 -04:00
f81ef89c61 enhancement to load dependencies from the /bin if they are not loaded automatically 2020-06-22 16:58:41 -04:00
6034a161e7 Fixed ThemeService using tenant aware api calls 2020-06-22 08:41:09 +02:00
ff23865711 Merge pull request #39 from oqtane/master
sync
2020-06-19 17:30:38 -04:00
3ac4116a84 Merge pull request #628 from thabaum/dashboard-table-col-size
Fix Dashboard button/input table col size
2020-06-19 17:29:27 -04:00
65df0549fd Merge pull request #625 from mikecasas/feature-email
Send notification based on a future datetime
2020-06-19 17:24:31 -04:00
04ffb079ea Merge pull request #630 from sbwalker/master
upgrade themes to latest Bootstrap, fix breaking change to ThemeBase due to IThemeControl being removed
2020-06-19 17:23:48 -04:00
99d99ca6ad upgrade themes to latest Bootstrap, fix breaking change to ThemeBase due to IThemeControl being removed 2020-06-19 17:22:26 -04:00
0659fc53b7 default launch settings 2020-06-18 23:16:18 -07:00
2febd81b4a default connection 2020-06-18 23:14:21 -07:00
0f814bfefe Update launchSettings.json 2020-06-18 23:06:33 -07:00
120066fce1 default 2020-06-18 23:01:59 -07:00
f4ca525bb5 Delete appsettings.json 2020-06-18 22:50:14 -07:00
5dced08f7a removes password autofill autocomplete="new-password" 2020-06-18 22:47:41 -07:00
882412b8ff button/input columns style="width: 1px" 2020-06-18 22:22:16 -07:00
563345638a Merge remote-tracking branch 'oqtane.framework-upstream/master' into dashboard-table-col-size 2020-06-18 18:14:15 -07:00
20b83c8809 Updated csproj. 2020-06-18 13:09:57 -04:00
7d89670930 Fixed the sql script file name and added update for null values. 2020-06-18 12:58:30 -04:00
40571bfb6e Bug Fix.
Not sure why the email address was not being added to the notification.
2020-06-18 08:40:43 -04:00
5a7a47ef27 Merge pull request #38 from oqtane/master
sync
2020-06-18 08:20:56 -04:00
ee5553ad8a Step 2. 2020-06-18 07:35:40 -04:00
ab8a1e7324 Step 1. 2020-06-18 06:13:15 -04:00
9e633d2d6d Merge pull request #624 from jimspillane/RemoveAsyncFromLoadJS
Remove async from scripts
2020-06-17 14:20:59 -04:00
975e7217a5 Remove async from scripts
Run SPA scripts synchronously to ensure load order
2020-06-17 12:25:36 -04:00
95053d8671 Merge pull request #18 from oqtane/master
Sync Master
2020-06-17 12:14:54 -04:00
61498862b5 Merge pull request #623 from sbwalker/master
add styling to install wizard
2020-06-17 11:29:25 -04:00
a57e25d3d3 add styling to install wizard 2020-06-17 11:27:44 -04:00
7cd18b1fe1 Merge pull request #622 from sbwalker/master
refactored script resource declaration to allow for bundling, made script loading async, refactored RichTextEditor to use new method
2020-06-17 10:28:26 -04:00
0636227284 refactored script resource declaration to allow for bundling, made script loading async, refactored RichTextEditor to use new method 2020-06-17 10:27:14 -04:00
d4d12b6f41 Merge pull request #621 from sbwalker/master
resolve #566 by moving Bootstrap declaration into theme
2020-06-16 17:39:15 -04:00
7c24bae753 resolve #566 by moving Bootstrap declaration into theme 2020-06-16 17:38:06 -04:00
06480d9a7e Merge pull request #619 from sbwalker/master
fix #618
2020-06-15 15:48:52 -04:00
71b3b695fc fix #618 2020-06-15 15:47:35 -04:00
db6d5d2b64 Merge pull request #616 from sbwalker/master
quick fix for #475 - cannot save role
2020-06-15 09:24:09 -04:00
7d7e8e9e66 quick fix for #475 - cannot save role 2020-06-15 09:22:35 -04:00
354382a580 Merge pull request #615 from sbwalker/master
minor cleanup
2020-06-14 22:10:25 -04:00
288cad3d3f minor cleanup 2020-06-14 22:08:52 -04:00
597a935cac Merge pull request #614 from sbwalker/master
added general exception UI handler for #605
2020-06-14 21:48:39 -04:00
1e4b2404c4 added general exception UI handler for #605 2020-06-14 21:47:11 -04:00
048d8f1b87 Merge pull request #613 from sbwalker/master
fix #595 - remove event log entry under scenario where a user is unauthenticated
2020-06-14 21:31:01 -04:00
ec416a7fef fix #595 - remove event log entry under scenario where a user is unauthenticated 2020-06-14 21:29:14 -04:00
c8630d7b05 Merge pull request #612 from sbwalker/master
fix #600 Unhandled exception opening a user's profile
2020-06-14 21:14:46 -04:00
42696eacbd fix #600 Unhandled exception opening a user's profile 2020-06-14 21:12:55 -04:00
b668a5d0ae Merge pull request #611 from sbwalker/master
migrate script naming convention
2020-06-14 13:07:05 -04:00
4285603563 migrate script naming convention 2020-06-14 13:06:33 -04:00
1c0d24ac25 Merge pull request #610 from sbwalker/master
refactoring of #518 to simplify registration of scripts in modules and themes
2020-06-14 12:08:05 -04:00
4e6b4a20ef refactoring of #518 to simplify registration of scripts in modules and themes 2020-06-14 12:07:16 -04:00
ea89cc1a64 Merge pull request #37 from oqtane/master
sync
2020-06-14 11:05:20 -04:00
79622819aa Merge pull request #609 from sbwalker/master
sync
2020-06-14 11:01:08 -04:00
88e3a9adc3 Merge pull request #608 from jimspillane/AddJavaScriptDependencyManager
Add JavaScript dependency manager
2020-06-14 11:00:27 -04:00
f0c95c46c9 Merge pull request #36 from oqtane/master
sync
2020-06-12 13:22:07 -04:00
1a0e8f7e19 Merge pull request #607 from chlupac/SiteRouterFix
small fixes
2020-06-12 13:04:44 -04:00
b5d4f8b176 Merge pull request #606 from chlupac/swagger
Add possibility to switch off swagger on production.
2020-06-12 13:02:58 -04:00
8053cc0af6 small fixes 2020-06-12 17:48:50 +02:00
134f21e29c Merge pull request #35 from oqtane/master
sync
2020-06-12 09:41:19 -04:00
a67330dbbb Merge pull request #586 from thabaum/patch-13
To/From Fields enabled/disabled, reply message fix
2020-06-12 09:40:16 -04:00
06820b9b63 Merge pull request #585 from thabaum/patch-12
'...' added, Reply Removed
2020-06-12 09:37:57 -04:00
f5d47a0308 Merge pull request #599 from BhanuKorthiwada/patch-1
Update README.md
2020-06-12 09:34:44 -04:00
937ae32a9e Add JS dependency manager
Added LoadJS(https://github.com/muicss/loadjs) and migrated Quill interop to use LoadJS.
2020-06-12 08:07:23 -04:00
5124dea72c Add JS dependency manager
Added LoadJS(https://github.com/muicss/loadjs) and migrated Quill interop to use LoadJS.
2020-06-10 21:09:10 -04:00
2ceeb25d0e Merge pull request #17 from oqtane/master
Sync upstream master
2020-06-10 12:20:54 -04:00
e2732d83bd Merge pull request #34 from oqtane/master
sync
2020-06-09 15:19:18 -04:00
3e56e9cc04 Update README.md 2020-06-09 09:57:09 +05:30
836c4505b9 fix bug #589 - Unhandled exception when trying to edit MyPage 2020-06-08 13:48:41 -04:00
ef5ae77060 Merge pull request #596 from svreic/FixingGetInstances
Fixed type filtering in assembly extensions
2020-06-08 13:47:19 -04:00
86b7fe193f Merge pull request #597 from sbwalker/master
fix bug #589 - Unhandled exception when trying to edit MyPage
2020-06-08 13:47:09 -04:00
3503f20255 Fixed type filtering in assembly extensions 2020-06-08 11:36:32 +02:00
51b69e05fb Original Message text area full bottom screen 2020-06-06 15:28:48 -07:00
095a95a3a9 removes message carriage returns 2020-06-06 11:46:35 -07:00
8d17153686 replace dashes with underscores 2020-06-06 08:03:42 -07:00
6efbeeb2b4 Change dashes to underscores 2020-06-06 08:02:08 -07:00
af1aab5b8d Updated to latest framework message username
addresses conflicts
2020-06-05 17:57:25 -07:00
f854b948ce namespaces removed last commit 2020-06-04 21:22:48 -07:00
7b9cd39cb7 To/From Fields enabled/disabled, reply message fix 2020-06-04 21:20:48 -07:00
6f6f2b77d7 '...' added, Reply Removed 2020-06-04 21:11:24 -07:00
ed2822ac7c fixed external module template to specify dependencies 2020-06-04 12:53:14 -04:00
41348b285d Merge pull request #583 from sbwalker/master
fixed external module template to specify dependencies
2020-06-04 12:51:40 -04:00
5b0da056b4 Restore support for third party assembly dependencies in modules and themes when running om Wasm 2020-06-04 12:48:29 -04:00
2d079bdc06 Merge pull request #582 from sbwalker/master
Restore support for third party assembly dependencies in modules and themes when running om Wasm
2020-06-04 12:47:14 -04:00
aed71fbf96 Add possibility to switch off swagger on production. 2020-06-04 07:10:45 +02:00
4ebdf5721c Merge pull request #33 from oqtane/master
sync
2020-06-03 19:47:04 -04:00
99cad13890 restrict user data leakage 2020-06-03 19:46:47 -04:00
4edb3f32f0 Merge pull request #580 from chlupac/UserManagerPersistence
User manager search persistence
2020-06-03 19:46:36 -04:00
01a3b7ed95 Merge pull request #581 from sbwalker/master
restrict user data leakage
2020-06-03 19:46:02 -04:00
c79199357e Merge pull request #579 from chlupac/StartupFix
Move module startup install up to allow install middleware
2020-06-03 19:45:47 -04:00
e24c6fc235 Move module startup install up to allow install middleware 2020-06-03 20:13:48 +02:00
cdc4de432a User manager search persistence 2020-06-03 20:10:52 +02:00
5544d2bed3 fix dynamic creation of remote script tags 2020-06-02 16:10:02 -04:00
aa4b00c900 Merge pull request #578 from sbwalker/master
fix dynamic creation of remote script tags
2020-06-02 16:08:34 -04:00
c4f1d37421 improve user experience after app restarts 2020-06-02 14:21:57 -04:00
c6b22d660b Merge pull request #577 from sbwalker/master
improve user experience after app restarts
2020-06-02 14:20:28 -04:00
ec11587b28 Merge pull request #32 from oqtane/master
sync
2020-06-01 14:58:41 -04:00
1b7ca45d4a Added support for friendly names and thumbnails in theme, layout, and container components. Added fallback support during loading for themes, layout, and containers. 2020-06-01 14:58:46 -04:00
01491b063d Merge pull request #574 from chlupac/OqtaneIgnore
OqtaneIgnore implementation fix
2020-06-01 14:58:04 -04:00
4142cc63e7 Merge pull request #576 from sbwalker/master
Added support for friendly names and thumbnails in theme, layout, and container components. Added fallback support during loading for themes, layout, and containers.
2020-06-01 14:57:21 -04:00
20dc749d05 Merge pull request #575 from chlupac/ControlPanel
Control panel Pane persistence & default selection fix.
2020-06-01 08:09:07 -04:00
4144be5323 Control panel Pane persistence & default selection fix. 2020-06-01 10:12:33 +02:00
27a3ac8d1c OqtaneIgnore implementation fix 2020-06-01 09:21:53 +02:00
f45cb8b069 fix theme selection in sites 2020-05-31 22:56:19 -04:00
0cc325ee95 Merge pull request #573 from sbwalker/master
fix theme selection in sites
2020-05-31 22:54:54 -04:00
7d21cfefc1 restrict container selection to the current theme, hide layout selection if theme does not support layouts, make behavior consistent for all theme/layout/container selection 2020-05-31 22:53:11 -04:00
652d46f64a Merge pull request #572 from sbwalker/master
restrict container selection to the current theme, hide layout selection if theme does not support layouts, make behavior consistent for all theme/layout/container selection
2020-05-31 22:52:05 -04:00
be4813d9c0 Merge pull request #31 from oqtane/master
sync
2020-05-31 20:45:12 -04:00
fe92d3d74f Merge pull request #538 from thabaum/patch-9
Site Settings: removes ONLY " <Select Container>"Theme and Layout drop down options
2020-05-31 20:42:25 -04:00
833ea9461a Merge pull request #568 from chlupac/ActionLink
Allow to show icon only in action link
2020-05-31 09:54:04 -04:00
47a917a3df Merge pull request #16 from oqtane/master
Sync master
2020-05-30 18:41:08 -04:00
cb484665ca Allow to show icon only in action link 2020-05-30 21:24:40 +02:00
64b0c2f128 Merge pull request #564 from sbwalker/master
addressed consistency between theme loading and moduledefinition loading, added theme detailed UI view
2020-05-29 16:27:04 -04:00
6402723d2a addressed consistency between theme loading and moduledefinition loading, added theme detailed UI view 2020-05-29 16:27:02 -04:00
b1a007491f Merge pull request #30 from oqtane/master
sync
2020-05-29 10:53:46 -04:00
17ef268594 Merge pull request #559 from chlupac/ThemeRepository
OqtaneIgnore implementation to theme elements
2020-05-29 10:42:33 -04:00
58d97dd731 OqtaneIgnore implementation to theme elements 2020-05-29 16:09:27 +02:00
ee3a4d1624 Merge pull request #556 from iJungleboy/patches/fix544
Patches/fix544
2020-05-29 08:38:22 -04:00
f9035f8fdf Update README.md 2020-05-28 17:32:06 -04:00
3a5b6954e3 fix for #525 when running locally without a network connection 2020-05-28 16:24:22 -04:00
1794d54a3f Merge pull request #557 from sbwalker/master
fix for #525 when running locally without a network connection
2020-05-28 16:23:15 -04:00
7d251b20cc Fix collection of theme information because of improper namespace checks
https://github.com/oqtane/oqtane.framework/issues/554
2020-05-28 21:07:30 +02:00
0f09df13b5 page redirect support and added missing unique indexes on database tables 2020-05-28 14:48:00 -04:00
73763f1623 Merge pull request #555 from sbwalker/master
page redirect support and added missing unique indexes on database tables
2020-05-28 14:46:36 -04:00
1b2c7772ef Merge pull request #29 from oqtane/master
sync
2020-05-28 14:39:10 -04:00
3b2583a1bd Merge pull request #553 from chlupac/HorizontalMenuFix
Horizontal menu fix
2020-05-28 14:37:24 -04:00
f7470e3c5b Horizontal menu fix 2020-05-28 20:00:28 +02:00
19f8b3d429 Merge pull request #28 from oqtane/master
sync
2020-05-28 10:30:12 -04:00
fd249a7734 Merge pull request #551 from chlupac/TryGetQueryValue
Uri extensions for read query values
2020-05-28 09:51:01 -04:00
d5f3b7513d Merge pull request #549 from chlupac/UserSearch
Search in User management
2020-05-28 09:45:45 -04:00
2a3b7caa9f Merge pull request #548 from jimspillane/FixWildcardRoute
Fix Alias name route
2020-05-28 09:45:34 -04:00
612a820dac fixed stylesheet and script removal logic 2020-05-28 09:44:41 -04:00
e80f42f1d9 Merge pull request #552 from sbwalker/master
fixed stylesheet and script removal logic
2020-05-28 09:43:23 -04:00
8b5004c628 Merge pull request #1 from oqtane/master
sync
2020-05-28 12:47:23 +02:00
151e37c470 Uri extensions for read query values
- safe way to check if key is presented
- safe parsing int values in query
- should replace int.Parse()

  _jobId = Int32.Parse(PageState.QueryString["id"]);
  can throw unhandled exception when "id" is not int

  correct way
  if (PageState.Uri.TryGetQueryValueInt("id",out _jobId)) ....
2020-05-28 12:26:23 +02:00
e935451d93 Search in User management 2020-05-28 11:33:47 +02:00
b0af00aa47 Fix Alias route
Added wildcard route catchall.
2020-05-27 16:58:50 -04:00
cbbac26881 Merge pull request #15 from oqtane/master
Sync upstream
2020-05-27 16:55:10 -04:00
f2230dd530 Merge pull request #544 from chlupac/nuget
Generate nugets in correct format
2020-05-27 16:12:51 -04:00
963148c639 Refactor Javascript and Stylesheet loading 2020-05-27 16:03:38 -04:00
215e52e42e Merge pull request #547 from sbwalker/master
Refactor Javascript and Stylesheet loading
2020-05-27 16:02:20 -04:00
945d7870c0 Merge pull request #14 from oqtane/master
Sync master
2020-05-26 18:46:49 -04:00
cc40733cff Merge pull request #27 from oqtane/master
sync
2020-05-26 10:39:21 -04:00
795f591da2 Generate nugets in correct format 2020-05-26 09:28:37 +02:00
4cab49e022 Merge pull request #535 from thabaum/patch-8
Oqtane Theme:  CSS style module actions dropdown text #fff
2020-05-25 11:33:07 -04:00
3b685fe571 Merge pull request #541 from jimspillane/ChangeJavaScriptNamespaceToOqtane
Change JavaScript namespace from interop to Oqtane
2020-05-25 11:32:54 -04:00
97df673609 Change JavaScript namespace from interop to Oqtane 2020-05-24 23:04:55 -04:00
cbcec0481a removed "Select Container, Theme, Layout" options 2020-05-24 19:12:47 -07:00
2f272ef4b6 style module actions dropdown text #fff 2020-05-24 17:47:27 -07:00
a4ed06f2fc Merge pull request #13 from oqtane/master
Sync upstream
2020-05-24 19:43:11 -04:00
3339690e2a Improvements to ModuleCreator external template to use Package references and include framework in Nuspec file 2020-05-24 19:11:35 -04:00
e4b37c17d8 Merge pull request #534 from sbwalker/master
Improvements to ModuleCreator external template to use Package references and include framework in Nuspec file
2020-05-24 19:10:21 -04:00
f1f07f45c6 Merge pull request #531 from chlupac/ControlPanel
Control panel persistence between module addings
2020-05-24 10:54:10 -04:00
068803615b Notification job fill mail subject 2020-05-22 21:29:52 +02:00
ddbb08ea75 Control panel state persistence 2020-05-22 21:29:06 +02:00
6ac2b64d7d improvements to module creator templates 2020-05-22 13:39:59 -04:00
93497eb776 Merge pull request #530 from sbwalker/master
improvements to module creator templates
2020-05-22 13:39:04 -04:00
e1b0dbcdf7 modification to JSInterop and Quill 2020-05-22 11:51:57 -04:00
c2ddd248e4 Merge pull request #529 from sbwalker/master
modification to JSInterop and Quill
2020-05-22 11:51:04 -04:00
a4ec456205 Merge branch 'master' of https://github.com/thabaum/Oqtane.Framework 2020-05-21 21:10:57 -07:00
23764d1ae4 Merge pull request #3 from oqtane/master
update
2020-05-21 21:07:22 -07:00
f77a8a964f Merge remote-tracking branch 'oqtane.framework-upstream/master' 2020-05-21 15:52:54 -07:00
c089b90659 modifications to JSInterop in RichTextEditor 2020-05-21 15:55:58 -04:00
32cd34b090 Merge pull request #522 from sbwalker/master
modifications to JSInterop in RichTextEditor
2020-05-21 15:54:53 -04:00
d8fca5de20 module creator templates need to be in the server project in order to be distributed with application 2020-05-20 15:31:09 -04:00
2f8a15fb89 Merge pull request #519 from sbwalker/master
module creator templates need to be in the server project in order to be distributed with application
2020-05-20 15:30:44 -04:00
1495a5c017 fixed references in external template 2020-05-20 14:59:57 -04:00
61b1b710db Merge pull request #517 from sbwalker/master
fixed references in external template
2020-05-20 14:58:56 -04:00
24579dc4d0 Merge pull request #12 from oqtane/master
Sync master
2020-05-20 13:04:32 -04:00
066ef44773 fixes to upgrade project 2020-05-20 11:57:41 -04:00
1355233b92 Merge pull request #515 from sbwalker/master
fixes to upgrade project
2020-05-20 11:56:32 -04:00
dc55c5b3ec Merge pull request #26 from oqtane/master
sync
2020-05-20 09:19:36 -04:00
ed3f07ff61 Merge pull request #514 from mikecasas/external-module-creator-refs
External module creator refs
2020-05-20 08:52:16 -04:00
028485b653 Merge remote-tracking branch 'upstream/master' into external-module-creator-refs 2020-05-20 08:06:18 -04:00
b43d191536 Merge pull request #25 from oqtane/master
sync
2020-05-20 08:03:39 -04:00
43dfad38c9 Merge pull request #513 from mikecasas/fix-01
Update reference.
2020-05-20 08:02:30 -04:00
6f1e930474 Updated the versions. 2020-05-20 06:51:22 -04:00
1d52de53a6 Update reference. 2020-05-20 06:47:57 -04:00
3aec68d9fa added border 2020-05-19 17:59:57 -04:00
4dc24f4c78 Merge pull request #511 from sbwalker/master
added border
2020-05-19 17:58:53 -04:00
a73e088abc Update README.md 2020-05-19 17:49:43 -04:00
b61446a50a updated screenshots 2020-05-19 17:49:11 -04:00
31773abb01 Merge pull request #510 from sbwalker/master
updated screenshots
2020-05-19 17:48:05 -04:00
85c491224d Update README.md 2020-05-19 14:55:52 -04:00
19fb3120d3 Update README.md 2020-05-19 14:18:43 -04:00
35b26c7525 update to version 1.0.0 2020-05-19 14:08:03 -04:00
4154bd0988 Merge pull request #509 from sbwalker/master
update to version 1.0.0
2020-05-19 14:07:10 -04:00
52b2c876a4 performance optimizations to avoid use of reflection ( thanks to @chlupac for this suggestion ) 2020-05-19 13:39:39 -04:00
b7eeda7562 Merge pull request #508 from sbwalker/master
performance optimizations to avoid use of reflection ( thanks to @chlupac for this suggestion )
2020-05-19 13:38:30 -04:00
b59e2533ea update to .NET Core 3.2 2020-05-19 12:48:30 -04:00
a8ec5e1265 Merge pull request #507 from sbwalker/master
update to .NET Core 3.2
2020-05-19 12:47:36 -04:00
61ff097f51 default theme needs to work in local development scenarios 2020-05-19 09:17:38 -04:00
b82f69b8b0 Merge pull request #506 from sbwalker/master
default theme needs to work in local development scenarios
2020-05-19 09:16:37 -04:00
263b045c75 module creator template updates 2020-05-19 09:08:29 -04:00
a160597f6f Merge pull request #505 from sbwalker/master
module creator template updates
2020-05-19 09:07:25 -04:00
f0fe6551dd Merge pull request #24 from oqtane/master
sync
2020-05-19 08:24:12 -04:00
09b17e142e Merge pull request #503 from jimspillane/FixMergeFiles
Fix file upload merge
2020-05-19 07:52:07 -04:00
b8ce634f85 Fix file upload merge
Allow upload of file names that match the token pattern ".part_", but not in the file extension. For example, a file named, a.part_Y.txt, would not be uploaded.
2020-05-18 19:53:49 -04:00
1532eb7586 Optimized downloading of assemblies when using WebAssembly 2020-05-18 18:02:23 -04:00
9b65cd0e07 Merge pull request #502 from sbwalker/master
Optimized downloading of assemblies when using WebAssembly
2020-05-18 18:01:23 -04:00
b4596cb624 Merge pull request #11 from oqtane/master
Sync upstream
2020-05-18 15:30:43 -04:00
5e23448618 use lambas for setting resources 2020-05-18 13:34:53 -04:00
96c2a59551 Merge pull request #501 from sbwalker/master
use lambas for setting resources
2020-05-18 13:33:50 -04:00
6ae019336d changing default theme to Oqtane theme 2020-05-18 10:44:54 -04:00
0c236682b9 Merge pull request #500 from sbwalker/master
changing default theme to Oqtane theme
2020-05-18 10:44:00 -04:00
9b74262c76 Added support for module resource management 2020-05-18 09:47:37 -04:00
a13208e65d Merge pull request #499 from sbwalker/master
Added support for module resource management
2020-05-18 09:46:32 -04:00
f8ab886750 Fixed issue with loading resources 2020-05-16 22:11:58 -04:00
84b011224e Merge pull request #498 from sbwalker/master
Fixed issue with loading resources
2020-05-16 22:11:00 -04:00
c426302242 enhanced module creator to display location where module will be created 2020-05-16 13:40:59 -04:00
814e2100b2 Merge pull request #495 from sbwalker/master
enhanced module creator to display location where module will be created
2020-05-16 13:39:57 -04:00
54d4447d23 Central management of resources ( ie. stylesheets and scripts ) 2020-05-16 12:00:15 -04:00
93942d7cdd Merge pull request #492 from jimspillane/AddMissingSInCsproj
Fix module pluralization
2020-05-16 12:00:08 -04:00
0afd7d9ca4 Merge pull request #493 from sbwalker/master
Central management of resources ( ie. stylesheets and scripts )
2020-05-16 11:59:24 -04:00
3a19ced2d1 Fix module pluralization
Added 's' to the module creator sql script in the csproj to fix compilation error.
2020-05-16 10:36:16 -04:00
d5811a20e9 Merge pull request #10 from oqtane/master
Sync master
2020-05-16 10:25:28 -04:00
1b2600c6c4 Merge pull request #23 from oqtane/master
sync
2020-05-16 08:54:28 -04:00
f9cdc6d70c Merge pull request #490 from jimspillane/AddFileValidation
Add File Name validation
2020-05-16 08:53:39 -04:00
fbdf21320b Merge pull request #491 from chlupac/SettingsService
Setting service bug.
2020-05-16 08:52:13 -04:00
96f5668a3b Setting service bug. 2020-05-16 08:40:30 +02:00
13adebb36c Add File Name validation
Apply file name validation rules to the File Controller and client.
2020-05-15 23:12:24 -04:00
8a1e83ff7f Modified the package installer to use target folders ( based on the Nuget specification ) rather than file extensions 2020-05-15 17:43:45 -04:00
e698ea4d36 Merge pull request #489 from sbwalker/master
Modified the package installer to use target folders  ( based on the Nuget specification ) rather than file extensions
2020-05-15 17:42:49 -04:00
f5ce00ae7d Merge pull request #9 from oqtane/master
Sync upstream master
2020-05-15 12:56:45 -04:00
3cbb6e3e6e enable module creator to add embeddedresources to csproj for internal modules 2020-05-15 12:36:52 -04:00
9394e77fd5 Merge pull request #488 from sbwalker/master
enable module creator to add embeddedresources to csproj for internal modules
2020-05-15 12:35:52 -04:00
ac03afb146 added ability to set default container at the page level, expanded size of role description in upgrade script for 0.9.2 2020-05-15 09:50:48 -04:00
51c27ae0e5 Merge pull request #486 from sbwalker/master
added ability to set default container at the page level, expanded size of role description in upgrade script for 0.9.2
2020-05-15 09:49:45 -04:00
0ea4c4d723 Merge pull request #484 from jimspillane/MoveFolderValidationToShared
Move Path and File validation to Shared Utilities
2020-05-15 09:47:37 -04:00
b3dee737b4 Merge pull request #480 from chlupac/FileManager
FileManager Tune-Up
2020-05-15 09:46:28 -04:00
24ca9f4ded Merge pull request #485 from chlupac/FileController
File Controller bug
2020-05-15 07:28:12 -04:00
9850e249fc File Controller bug 2020-05-15 08:20:00 +02:00
5e04cb18a4 File Manager Tune-up 2020-05-15 08:18:07 +02:00
39641804f1 Move Path and File validation to Shared Utilities
Created extension methods:
IsPathValid(Folder)
IsFileValid(File)
IsPathOrFileValid(string)

Added client side validation check for Folders.
2020-05-14 22:02:57 -04:00
edc356292d Merge pull request #481 from thabaum/patch-6
container class added to pane
2020-05-14 21:34:09 -04:00
78f4af6b70 Merge pull request #482 from thabaum/patch-7
System Info input disabled changed to readonly
2020-05-14 18:41:36 -04:00
e98b8801f3 Merge pull request #483 from sbwalker/master
removed redundant assembly download logic, added security on download controller methods
2020-05-14 18:41:15 -04:00
caabac3e74 removed redundant assembly download logic, added security on download controller methods 2020-05-14 18:40:53 -04:00
422f360807 disabled changed to readonly 2020-05-14 14:58:09 -07:00
6e28fa47a2 container class added to pane
resolves issue with title border DIV not utilizing 100% pane size
2020-05-14 14:03:09 -07:00
b4f3c4ae56 Merge pull request #22 from oqtane/master
sync
2020-05-14 14:22:15 -04:00
bafe2c6666 fix module creator templates 2020-05-14 14:22:11 -04:00
5eec442442 Merge pull request #479 from sbwalker/master
fix module creator templates
2020-05-14 14:21:28 -04:00
def12489e6 Merge pull request #8 from oqtane/master
Sync master
2020-05-14 12:12:26 -04:00
82429c2545 Merge pull request #477 from jimspillane/PathTraversal
Add File and Path rules
2020-05-14 11:55:07 -04:00
aa97dd4d0d Allow modules to be installed/uninstalled with embedded scripts or IInstallable interface. Fix module uninstall issues. 2020-05-14 11:54:28 -04:00
cba5865e81 Merge pull request #478 from sbwalker/master
Allow modules to be installed/uninstalled with embedded scripts or IInstallable interface. Fix module uninstall issues.
2020-05-14 11:53:33 -04:00
8afe8e7474 Add File and Path rules
Apply the file and path naming rules found at 
https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file

Mitigate path traversal.
2020-05-14 09:53:36 -04:00
a9630e715b Merge pull request #7 from oqtane/master
Sync upstream master
2020-05-14 08:43:53 -04:00
6824b3f1b5 Merge pull request #471 from jimspillane/ReservedNameCheck
Add additional reserved names and characters
2020-05-13 16:25:27 -04:00
1cca18c4d2 Add additional reserved names and characters
Added CONIN$,CONOUT$ and characters <>:"/\|?*

Added .Split('.')[0] to folder.Name to catch names like CON.txt and allow names like CONTRACT.
2020-05-12 22:38:28 -04:00
a886ae12cc Merge pull request #6 from oqtane/master
Sync master
2020-05-12 20:52:07 -04:00
560c995564 Include AliasId in service API calls ( this is not needed for interacting with the MasterDB repository however it is needed for tenant-based logging ) 2020-05-12 20:31:31 -04:00
69a5077eda Merge pull request #470 from sbwalker/master
Include AliasId in service API calls ( this is not needed for interacting with the MasterDB repository however it is needed for tenant-based logging )
2020-05-12 20:30:27 -04:00
3efd39c74f Merge pull request #21 from oqtane/master
sync
2020-05-12 20:08:55 -04:00
bbcb054f7a Merge pull request #469 from chlupac/IClientStartup
Client assembly selection criteria changed
2020-05-12 20:07:27 -04:00
88cf30f7c6 Merge branch 'master' of https://github.com/oqtane/oqtane.framework into IClientStartup 2020-05-12 23:20:06 +02:00
4c188b782d ClientAssembly selection criteria changed 2020-05-12 23:17:37 +02:00
196e3d5865 Merge pull request #468 from sbwalker/master
updated module creator templates to use dependency injection in module components
2020-05-12 16:38:47 -04:00
6fd0efbb73 updated module creator templates to use dependency injection in module components 2020-05-12 16:31:53 -04:00
9eec0fd86b updated HtmlText module to use dependency injection 2020-05-12 15:04:07 -04:00
ad70128747 Merge pull request #466 from sbwalker/master
updated HtmlText module to use dependency injection
2020-05-12 15:04:01 -04:00
ee55b4e3cf Merge pull request #465 from sbwalker/master
add security to site template API
2020-05-12 14:38:52 -04:00
53f454e370 Merge pull request #20 from oqtane/master
sync
2020-05-12 14:37:37 -04:00
f05c7d79e3 add security to site template API 2020-05-12 14:31:18 -04:00
598b433cd2 Merge pull request #463 from chlupac/IClientStartup
IClientStartup  implementation
2020-05-12 14:31:10 -04:00
6ac4ba4617 Merge pull request #462 from mikecasas/patch-1
Update IModuleControl.cs
2020-05-12 14:30:59 -04:00
f4710f90c0 Merge pull request #464 from sbwalker/master
validate folder names, handle missing files more gracefully
2020-05-12 14:30:44 -04:00
6f3fe8d933 validate folder names, handle missing files more gracefully 2020-05-12 13:24:51 -04:00
da73d519d7 IClientStartup implementation 2020-05-12 10:00:28 +02:00
7f157582cc Update IModuleControl.cs
Added additional comments.
2020-05-11 13:47:12 -04:00
4d7ec16f36 Merge pull request #459 from chlupac/IServerStartup
IServerStartup implementation
2020-05-11 12:56:22 -04:00
7c814a67b3 IServerStartup implementation 2020-05-11 11:19:12 +02:00
c83496d814 Merge pull request #19 from oqtane/master
sync
2020-05-10 10:03:50 -04:00
83d47376cc Merge pull request #458 from jimspillane/FixContainsFiles
Fix contains files
2020-05-10 09:43:59 -04:00
a1449fb2dd Fix Uploadable files
When testing for allowable file extensions using a comma separated list, like (jpg,mp3,txt,zip), extensions such as .xt or .p3 will return true.  Adding Split(',') will test each of the extensions correctly.

Adding ToLower() will allow mixed case extensions, like .JPG or .Zip to return true.
2020-05-09 14:58:39 -04:00
2362faaee1 Merge pull request #5 from oqtane/master
Sync master
2020-05-09 14:04:36 -04:00
f6f895b516 more responsive design adjustments 2020-05-09 12:16:39 -04:00
8516e328f7 Merge pull request #457 from sbwalker/master
more responsive design adjustments
2020-05-09 12:15:41 -04:00
043f8d07de Merge pull request #18 from oqtane/master
sync
2020-05-08 17:30:44 -04:00
c2ed71ab0d added classes to all theme controls, added mobile support to Oqtane theme 2020-05-08 17:30:35 -04:00
552df0c9fc Merge pull request #455 from chlupac/NewVersion
Ignore abstract classes at loading
2020-05-08 17:30:06 -04:00
c5d12d0430 Merge pull request #456 from sbwalker/master
added classes to all theme controls, added mobile support to Oqtane theme
2020-05-08 17:29:51 -04:00
1e270e6423 Ignore abstract classes at loading 2020-05-08 21:30:31 +02:00
aaf2c96374 minor fix for placeholder content 2020-05-08 12:25:37 -04:00
86309dc264 Merge pull request #453 from sbwalker/master
minor fix for placeholder content
2020-05-08 12:24:46 -04:00
051534b80c resolved #270 - migrated raw html entry into richtexteditor control 2020-05-08 12:17:06 -04:00
d3ce5bc17c Merge pull request #452 from sbwalker/master
resolved #270 - migrated raw html entry into richtexteditor control
2020-05-08 12:16:17 -04:00
97354a9525 Update README.md 2020-05-08 08:34:31 -04:00
f07146fd50 updated external module template to support new assembly loading criteria, fixed minor issue in assembky loading logic 2020-05-07 16:24:36 -04:00
5b08cac48d Merge pull request #451 from sbwalker/master
updated external module template to support new assembly loading criteria, fixed minor issue in assembky loading logic
2020-05-07 16:23:56 -04:00
d53bdc5bb6 Merge pull request #17 from oqtane/master
sync with upstream
2020-05-07 15:28:39 -04:00
a63a659888 Merge pull request #419 from chlupac/BootswatchCdn
Bootswatch themes in Oqtane.Themes.OqtaneTheme CDN version
2020-05-07 15:25:03 -04:00
d6f3fd108b Merge pull request #449 from chlupac/LoadOptimalization
Simplified loading of oqtane assemblies
2020-05-07 15:09:32 -04:00
47f17a589f implementation of [OqtaneIgnore] class attribute in controls 2020-05-07 21:02:43 +02:00
d7ad175cd7 fixes for framework upgrade, fixes for control panel CSS styles, added AllPages attrubute for Modules, bumped version to 0.9.1 to test upgrades 2020-05-07 14:38:24 -04:00
d58b6e5d83 Merge pull request #450 from sbwalker/master
fixes for framework upgrade, fixes for control panel CSS styles, added AllPages attrubute for Modules, bumped version to 0.9.1 to test upgrades
2020-05-07 14:37:49 -04:00
e78a5e090d Bootswatch themes in Oqtane.Themes.OqtaneTheme
Theme is set in Oqtane.Client\Themes\OqtaneTheme\Default.razor
```
    protected override async Task OnParametersSetAsync()
    {
    // go to https://www.bootstrapcdn.com/bootswatch/ and take your favorite theme
    //<link href="https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/cyborg/bootstrap.min.css" rel="stylesheet" integrity="sha384-l7xaoY0cJM4h9xh1RfazbgJVUZvdtyLWPueWNtLAphf/UbBgOVzqbOTogxPwYLHM" crossorigin="anonymous">
        await LoadBootstrapTheme("https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/cyborg/bootstrap.min.css","sha384-l7xaoY0cJM4h9xh1RfazbgJVUZvdtyLWPueWNtLAphf/UbBgOVzqbOTogxPwYLHM");
        await IncludeCSS("Theme.css");
    }
```
2020-05-07 12:17:44 +02:00
71f79bd90b Merge pull request #1 from oqtane/master
update master branch
2020-05-06 17:55:24 -07:00
7ca1f92f52 Merge pull request #4 from oqtane/master
Sync master
2020-05-05 21:26:18 -04:00
c394c6ea7a Resolved authentication issue #441 related to alias refactoring #439, fixed breaking change in .NET Core 3.2 related to Blazor WebAssembly identification 2020-05-05 16:28:50 -04:00
6586883979 Merge pull request #445 from sbwalker/master
Resolved authentication issue #441 related to alias refactoring #439, fixed breaking change in .NET Core 3.2 related to Blazor WebAssembly identification
2020-05-05 16:27:52 -04:00
e09fcd7e42 added CreateApiUrl method back for backward compatibility 2020-05-05 09:47:23 -04:00
b5aa6c5a48 Merge pull request #440 from sbwalker/master
added CreateApiUrl method back for backward compatibility
2020-05-05 09:46:48 -04:00
00bf917f6c Merge pull request #435 from thabaum/patch-1
Log details displayed from disabled to readonly
2020-05-05 09:15:48 -04:00
a02cfea6c9 improve performance of alias handling and allow aliases to be an unlimited number of subfolders in depth 2020-05-05 09:15:36 -04:00
db33a91c4b Merge pull request #439 from sbwalker/master
improve performance of alias handling and allow aliases to be an unlimited number of subfolders in depth
2020-05-05 09:15:01 -04:00
8f1a3c99c3 changed displayed input to readonly
Fixes issue of unable to select information displayed from input and textarea changing the select property from disabled to readonly
2020-05-04 12:14:51 -07:00
bf84f12471 fixed theme/layout handling in Add/Edit Page 2020-05-03 11:39:34 -04:00
979680f46d Merge pull request #431 from sbwalker/master
fixed theme/layout handling in Add/Edit Page
2020-05-03 11:38:52 -04:00
c30ee60433 Merge pull request #3 from oqtane/master
Sync master
2020-05-01 18:07:34 -04:00
922c7796f2 Merge pull request #429 from sbwalker/master
fixed module action import/export, improved module installation
2020-05-01 15:58:54 -04:00
45aeb17020 fixed module action import/export, improved module installation 2020-05-01 15:58:34 -04:00
e627e14233 Merge pull request #2 from oqtane/master
Sync master
2020-05-01 14:50:51 -04:00
3afa489f22 upgrade to .NET Core 3.2 RC 2020-05-01 11:32:41 -04:00
a34e2521c6 Merge pull request #428 from sbwalker/master
Upgrade to .NET Core 3.2 RC
2020-05-01 11:32:04 -04:00
7c6dc6d774 Added ability to execute version specific code during framework upgrade (removed ApplicationVersion table and replaced with Version field on Tenant table), updated version number to 0.9.0 and renamed install scripts to match - this will be a baseline release which will be upgradeable 2020-05-01 10:27:14 -04:00
e7a2eaa2dc Merge pull request #427 from sbwalker/master
Added ability to execute version specific code during framework upgrade (removed ApplicationVersion table and replaced with Version field on Tenant table), updated version number to 0.9.0 and renamed install scripts to match - this will be a baseline release which will be upgradeable
2020-05-01 10:26:41 -04:00
dda7121883 Merge pull request #16 from oqtane/master
sync
2020-05-01 08:08:01 -04:00
03592da08f Merge pull request #426 from chlupac/DbUpfixes
Page editor fix & Script check
2020-05-01 08:05:53 -04:00
1ed730cafe Merge pull request #15 from oqtane/master
sync
2020-05-01 08:02:05 -04:00
d387e6e573 Page editor fix
Script check
2020-05-01 11:24:10 +02:00
4a6b12b6f9 Merge pull request #1 from oqtane/master
Sync master
2020-04-30 21:07:21 -04:00
573c623592 fixes to module templates 2020-04-30 14:36:30 -04:00
aacb2a0563 Merge pull request #423 from sbwalker/master
fixes to module templates
2020-04-30 14:36:07 -04:00
723855b94c Merge pull request #420 from chlupac/ModuleTemplateFix
ModuleCreator: WebAssembly references causes build error in some scenarios.
2020-04-30 14:04:44 -04:00
e0ee2419e7 Merge pull request #421 from SPSeanLong/master
Fixed add profile property
2020-04-30 14:03:18 -04:00
34538dd945 install/upgrade refactoring to consolidate all use cases and implement IInstallable interface for modules, moved tenant creation to site management UI, fixed z-order issues in Blazor theme, enhanced JS Interop methods to support integrity and crossorigin 2020-04-30 13:58:04 -04:00
ac6ee7f4b0 Merge pull request #422 from sbwalker/master
install/upgrade refactoring to consolidate all use cases and implement IInstallable interface for modules, moved tenant creation to site management UI, fixed z-order issues in Blazor theme, enhanced JS Interop methods to support integrity and crossorigin
2020-04-30 13:57:30 -04:00
3be19df4a5 Fixed add profile property 2020-04-29 20:49:12 -04:00
dec6658047 Merge pull request #2 from oqtane/master
Rebase
2020-04-29 20:28:27 -04:00
4e5ca01ebd WebAssembly references causes build error in some scenarios. Works without them.
https://gitter.im/aspnet/Blazor?at=5e915f6ee24b4d6c44fe1827
2020-04-29 21:55:12 +02:00
099fddf2b6 Merge pull request #14 from oqtane/master
sync
2020-04-28 09:25:31 -04:00
eebe5d8d8c Merge pull request #416 from chlupac/SiteInstall
Get custom theme and layout on a default install
2020-04-28 09:02:55 -04:00
e0389f809b Merge pull request #414 from chlupac/ComponentRefactoring
Theme base components refactoring - clear of async warnings
2020-04-28 08:58:44 -04:00
375c706029 Get custom theme and layout on a default install 2020-04-28 14:51:27 +02:00
e29b4f9d8d Theme base components refactoring - clear of async warnings 2020-04-27 22:43:24 +02:00
e6c26210a0 z-order tweak to Blazor theme 2020-04-27 15:31:32 -04:00
e0edc6b3f9 Merge pull request #413 from sbwalker/master
z-order tweak to Blazor theme
2020-04-27 15:30:52 -04:00
7a6cc0c76e Merge pull request #13 from oqtane/master
sync
2020-04-27 15:07:12 -04:00
f76b260d6c Merge pull request #411 from chlupac/ComponentRefactoring
Theme base components refactoring
2020-04-27 14:25:57 -04:00
1ebe678d45 Merge branch 'master' into ComponentRefactoring 2020-04-27 14:25:09 -04:00
d2fd8c7f4e improved responsive design for Blazaor theme to make it more mobile friendly 2020-04-27 14:18:58 -04:00
2ce627cdce Merge pull request #412 from sbwalker/master
improved responsive design for Blazaor theme to make it more mobile friendly
2020-04-27 14:18:37 -04:00
ced2051704 Theme base components refactoring 2020-04-27 19:28:58 +02:00
8523f0d719 Update LICENSE 2020-04-27 08:20:58 -04:00
bb2077cb42 Merge pull request #12 from oqtane/master
sync
2020-04-27 08:19:53 -04:00
dee25cc376 Merge pull request #408 from chlupac/ComponentRefactoring
Menu component refactoring
2020-04-27 08:19:12 -04:00
cf567ee152 Update README.md 2020-04-27 08:18:13 -04:00
18aafda970 Merge pull request #11 from oqtane/master
sync
2020-04-27 08:16:21 -04:00
8dd2677b8f Menu component refactoring
Login component refactoring
2020-04-27 10:05:13 +02:00
7097caad69 Merge pull request #409 from mikecasas/feature-update-preview5
Update to Preview 5.
2020-04-26 19:21:27 -04:00
43a94eb60a Fix for the correct version. 2020-04-26 16:16:40 -04:00
fa91a2fd46 Update to Preview 5. 2020-04-26 14:52:39 -04:00
6b2411b396 fixed merge issue 2020-04-26 13:39:56 -04:00
d29cd1f949 Merge pull request #407 from sbwalker/master
fixed merge issue
2020-04-26 13:39:27 -04:00
1fb7ab557e Merge pull request #10 from oqtane/master
sync
2020-04-26 13:28:38 -04:00
c7b3aaf32f Merge pull request #387 from SPSeanLong/master
OS independent file paths
2020-04-26 13:27:26 -04:00
df3afb1e21 Merge branch 'master' into master 2020-04-26 13:27:16 -04:00
6d93fcfc1c Merge pull request #401 from chlupac/DatabaseManagerBug
Create Data directoty if does not exists
2020-04-26 13:21:42 -04:00
9a7bde4357 Merge pull request #402 from hishamco/preview5
Updated to Blazor WebAssembly 3.2 preview 5
2020-04-26 13:20:50 -04:00
779bb7aad5 Merge pull request #403 from hishamco/fix#396
Render line break conditionally in HtmlText module
2020-04-26 13:20:33 -04:00
f297fadf13 Merge pull request #405 from chlupac/PermissionOptimalization
Permission Optimalization
2020-04-26 13:20:02 -04:00
06db9efc08 Merge branch 'master' into PermissionOptimalization 2020-04-26 13:19:54 -04:00
11790a0b64 Merge pull request #406 from sbwalker/master
Added IInstallable interface and uninstall implementation for modules. Refactoring module installation to use interface still in progress.
2020-04-26 13:16:37 -04:00
58d3c406cd added IInstallable interface and uninstall implementation for modules. Refactoring module installation to use interface still in progress. 2020-04-26 13:15:02 -04:00
7606e7b488 Permission Optimalization 2020-04-26 16:19:20 +02:00
967f92c1aa Render line break conditionally in HtmlText module 2020-04-25 17:35:50 +03:00
91d1e7c684 Updated to Blazor WebAssembly 3.2 preview 5 2020-04-25 17:25:20 +03:00
a09be84824 Create Data directoty if does not exists 2020-04-25 10:58:38 +02:00
e4850c4d27 Merge pull request #9 from oqtane/master
sync
2020-04-23 10:08:32 -04:00
3f9b112ea6 Merge pull request #398 from hishamco/remove-wwwroot
Remove wwwroot from Oqtane.Client
2020-04-23 10:07:34 -04:00
6790dfe9a2 Merge pull request #393 from hishamco/preview4
Updated to Blazor WebAssembly 3.2 preview 4
2020-04-23 10:07:18 -04:00
82129eebbf Update README.md 2020-04-23 10:06:24 -04:00
2278e49983 Remove wwwroot from Oqtane.Client 2020-04-23 03:36:32 +03:00
845d38caf6 Remove AddBaseAddressHttpClient() 2020-04-23 00:22:12 +03:00
457debf35e Update README.md 2020-04-22 08:28:05 -04:00
494b0bb1f0 Merge pull request #8 from oqtane/master
sync to upstream
2020-04-21 15:20:52 -04:00
62a7c0e584 Merge pull request #392 from hishamco/remove-unnecessary-modules
Remove unnecessary modules
2020-04-21 15:19:51 -04:00
1abfeea0d5 Merge pull request #394 from sbwalker/master
Security fixes for Site Administrators to ensure proper access. Improvements to User and Role management components. Fix logic in CreateUser so that it does not prevent Administrators from creating users.
2020-04-21 15:17:30 -04:00
79eae9c5fa Merge branch 'master' into master 2020-04-21 15:17:22 -04:00
ab5257cea2 Security fixes for Site Administrators to ensure proper access. Improvements to User and Role management components. Fix logic in CreateUser so that it does not prevent Administrators from creating users. 2020-04-21 15:16:12 -04:00
f83778fd70 Updated to Blazor WebAssembly 3.2 preview 4 2020-04-21 19:56:24 +03:00
ed0cc42852 Remove unnecessary modules 2020-04-21 19:02:06 +03:00
72995cd8fa added system info admin page/module, improved UI for framework, module, and theme install/upgrade, added version to ModuleDefinitions, fixed bug in logging logic introduced during code standardization 2020-04-20 18:05:37 -04:00
22b0f42461 Merge pull request #391 from sbwalker/master
added system info admin page/module, improved UI for framework, module, and theme install/upgrade, added version to ModuleDefinitions, fixed bug in logging logic introduced during code standardization
2020-04-20 18:05:01 -04:00
f0043f53ee OS independent file paths & Utility.PathCombine added
System.IO.Path.Combine provides cross-platform support for system paths, however rooted paths discarding of earlier segments
Utilities.PathCombine ensures if any parameters start with root chacters does not discard previous Utilities.PathCombine allows appending of "\\" to translate to the correct cross-platform result
2020-04-18 14:57:31 -04:00
194f5674b4 Merge branch 'master' of https://github.com/SPSeanLong/oqtane.framework 2020-04-18 12:59:51 -04:00
c07ebdd41b Revert "Updated for consistant delimiter presence with source"
This reverts commit ce118096b7.
2020-04-18 12:54:12 -04:00
ce118096b7 Updated for consistant delimiter presence with source 2020-04-18 12:53:41 -04:00
46b205102a Merge pull request #1 from oqtane/master
Update to match source
2020-04-18 12:22:30 -04:00
62987ca72f allow users to modify default module names, descriptions, and categories and improve control panel behavior 2020-04-18 10:51:07 -04:00
b84db01810 Merge pull request #389 from sbwalker/master
allow users to modify default module names, descriptions, and categories and improve control panel behavior
2020-04-18 10:50:54 -04:00
50611582df Merge pull request #386 from chlupac/DBCreationBug
Database creation bug
2020-04-18 08:47:12 -04:00
69ceb5dd42 HostUser change is not allowed in silent install 2020-04-18 11:11:44 +02:00
209f6db0fb Database creation bug
HostUser change is not allowed in silent install
2020-04-17 22:29:39 +02:00
70502cd881 OS independent file paths 2020-04-17 16:25:00 -04:00
f56d1fe543 improving admin components 2020-04-17 12:59:53 -04:00
2dd2216aa2 Merge pull request #385 from sbwalker/master
improving admin components
2020-04-17 12:59:27 -04:00
5fec03627e Merge pull request #384 from sbwalker/master
changed ServerAssemblyName to ServerManagerType to optimize processing
2020-04-16 22:28:22 -04:00
b9d70dd11a changed ServerAssemblyName to ServerManagerType to optimize processing 2020-04-16 22:27:12 -04:00
f5e4c1dd29 fixed user registration, and updated module creator templates to use new Service approach 2020-04-16 10:21:16 -04:00
5fb8cd5cec Merge pull request #381 from sbwalker/master
fixed user registration, and updated module creator templates to use new Service approach
2020-04-16 10:20:57 -04:00
3d21a6e204 Merge pull request #7 from oqtane/master
sync
2020-04-16 09:44:26 -04:00
496773a702 Merge pull request #379 from chlupac/Json3
Migration to using System.Net.Http.Json; part two
2020-04-16 08:15:25 -04:00
69bfd6f0e8 Migration to using System.Net.Http.Json; part two
- some cosmetics and bugs,
 - logging preparation,
 - error checking
 - Fixed bug with site.AllowRegistration in case of installation
2020-04-16 10:04:02 +02:00
7048ed9bbc Merge pull request #6 from oqtane/master
sync
2020-04-15 20:12:33 -04:00
4d08573c37 Merge pull request #378 from chlupac/json2
Migration to using System.Net.Http.Json; part one - functional migration
2020-04-15 20:11:51 -04:00
95e9bee4e2 Migration to using System.Net.Http.Json; part one - functional migration 2020-04-15 23:07:27 +02:00
a70c6de1e9 Update README.md 2020-04-15 17:01:01 -04:00
465b572679 Merge pull request #5 from oqtane/master
sync
2020-04-15 16:19:43 -04:00
fe2ad29b3b Merge pull request #374 from mikecasas/fix-register
Fix register
2020-04-15 16:18:57 -04:00
209fee9c8a Merge pull request #375 from jimspillane/master
Fix Notifications parameters
2020-04-15 12:49:35 -04:00
ddeea8e9e2 Merge pull request #376 from chlupac/No204
Return JSON null instead of 204 status from controller
2020-04-15 12:49:23 -04:00
72965cfbb2 Return JSON null instead of 204 stantus from controller
Services GET returns null instead of exception :)
2020-04-15 12:34:43 +02:00
1b373a4bfa Added site service to be able to get the site properties. 2020-04-15 05:52:57 -04:00
5232762c0d Fix Notifications parameters
Removed space causing siteid to always send null.
2020-04-14 21:51:22 -04:00
85343ade60 Hide the container if registration is disabled. 2020-04-14 17:04:26 -04:00
5b48240322 If site does not allow registration then disable it. 2020-04-14 16:55:03 -04:00
2c54bcd80e minor modifications to external module template 2020-04-14 16:34:41 -04:00
b4f63acadd Merge pull request #373 from sbwalker/master
minor modifications to external module template
2020-04-14 16:34:20 -04:00
80c7ab1e8e Enhancement to load debugging symbols ( *.pdb ) if they exist in the /bin folder. This enables debugging of modules. 2020-04-14 14:46:44 -04:00
5389629efc Merge pull request #371 from sbwalker/master
Enhancement to load debugging symbols ( *.pdb ) if they exist in the /bin folder. This enables debugging of modules.
2020-04-14 14:46:37 -04:00
70ebd6eb35 added defensive coding to deal with scenarios where files are deleted but still references from other entities 2020-04-14 12:18:11 -04:00
4bb906a316 Merge pull request #370 from sbwalker/master
added defensive coding to deal with scenarios where files are deleted but still references from other entities
2020-04-14 12:17:44 -04:00
de5eeb08c4 Merge pull request #4 from oqtane/master
sync
2020-04-14 12:13:59 -04:00
6ea641014e Merge pull request #369 from mikecasas/fix-site-template
Fix empty string for default site template.
2020-04-14 12:13:10 -04:00
57aa8b6cbd Fix empty string for default site template. 2020-04-14 11:02:42 -04:00
932fc97638 Merge pull request #368 from aubrey-b/site-template
Fix null value for site template.
2020-04-13 14:05:08 -04:00
c7a9d6c278 Fix null value for site template. 2020-04-13 13:54:03 -04:00
f41dd06f6d fixed external module template so that it generates folder paths correctly 2020-04-13 12:48:49 -04:00
060d449076 Merge pull request #367 from sbwalker/master
fixed external module template so that it generates folder paths correctly
2020-04-13 12:48:26 -04:00
c25615546a fix to not execute uninstall script when creating a module from template 2020-04-13 08:01:25 -04:00
0d153e9a90 Merge pull request #366 from sbwalker/master
fix to not execute uninstall script when creating a module from template
2020-04-13 08:01:03 -04:00
1ed8f4554a added uninstall script to external module template as embedded resource 2020-04-12 20:12:10 -04:00
e5edb23dd8 Merge pull request #365 from sbwalker/master
added uninstall script to external module template as embedded resource
2020-04-12 20:11:48 -04:00
482747627e added uninstall support for modules 2020-04-12 20:08:19 -04:00
7f9b1e596f Merge pull request #364 from sbwalker/master
added uninstall support for modules
2020-04-12 20:08:11 -04:00
112397c9de fix regression bug related to transition to PermissionNames constants 2020-04-12 10:12:48 -04:00
75eee3e950 Merge pull request #363 from sbwalker/master
fix regression bug related to transition to PermissionNames constants
2020-04-12 10:12:22 -04:00
f763fbd058 Merge pull request #3 from oqtane/master
sync
2020-04-12 10:07:44 -04:00
f792e7e1c1 Merge pull request #362 from chlupac/PackageUnpack
Solution of warning about additional singleton of InstallManager
2020-04-12 09:53:29 -04:00
94cab7d4db Solution of warning
"Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to 'Configure'"
2020-04-12 11:14:59 +02:00
dbcb973119 fixes to emable module package installation from wwwroot/modules 2020-04-11 14:02:42 -04:00
68e200cb4c Merge pull request #360 from sbwalker/master
fixes to emable module package installation from wwwroot/modules
2020-04-11 14:02:20 -04:00
93a09f6db8 Merge pull request #2 from oqtane/master
sync
2020-04-11 11:07:39 -04:00
139e33b539 Merge pull request #351 from chlupac/InstallModuleBug
nuget module installation fix
2020-04-11 11:06:34 -04:00
7c2252f0b4 Merge pull request #359 from user-jwalker/master
help text update
2020-04-11 11:06:18 -04:00
89066ecfd0 help text update 2020-04-10 21:49:57 -04:00
252d5ff2af Merge pull request #1 from oqtane/master
sync
2020-04-10 17:14:47 -04:00
8f4fd6f135 minor improvements to field level help 2020-04-10 14:18:22 -04:00
ef1d0852ba Merge pull request #358 from sbwalker/master
minor improvements to field level help
2020-04-10 14:17:59 -04:00
90a127fbb8 enhancements to ModuleCreator so that it can scaffold internal and external modules 2020-04-10 13:49:50 -04:00
b1d15ac22c Merge pull request #357 from sbwalker/master
enhancements to ModuleCreator so that it can scaffold internal and external modules
2020-04-10 13:49:48 -04:00
728bd23f5d Merge pull request #354 from sbwalker/master
NavigateUrl fix to deal with scenario where alias has a value and path is ""
2020-04-08 13:35:52 -04:00
1edc34dca0 NavigateUrl fix to deal with scenario where alias has a value and path is "" 2020-04-08 11:43:42 -04:00
c5aaccca76 Merge pull request #353 from sbwalker/master
fixed issue with module settings tab and module creator templating
2020-04-07 17:25:57 -04:00
c29195b417 fixed issue with module settings tab and module creator templating 2020-04-07 17:25:57 -04:00
0714ba9ece Merge pull request #1 from oqtane/master
sync
2020-04-07 10:55:37 -04:00
532a33ff47 Merge pull request #336 from hishamco/navigate-url
Simplify NavigateUrl using UriBuilder
2020-04-07 10:53:52 -04:00
6d0043669c nuget module installation fix II 2020-04-07 16:44:38 +02:00
3fc7e78e56 nuget module installation fix 2020-04-07 11:21:33 +02:00
bda6409328 Merge pull request #350 from user-jwalker/master
update helptext
2020-04-06 16:12:56 -04:00
9fff8be40a update helptext 2020-04-06 16:00:58 -04:00
e10015c11a Address feedback 2020-04-06 20:54:55 +03:00
7421df2970 fixed issues when running on WebAssembly, made IModule implementations consistent 2020-04-06 13:25:19 -04:00
706290b098 Merge pull request #347 from sbwalker/master
fixed issues when running on WebAssembly, made IModule implementations consistent
2020-04-06 13:25:08 -04:00
898bf38156 Merge pull request #346 from chlupac/InstallModuleBug
Fix of tenant migration and module installation
2020-04-06 11:42:36 -04:00
b15ff4732c Fix of tenant migration and module installation 2020-04-06 08:53:52 +02:00
5a6f939a98 modified ITheme interface (#344)
* upgrade to .NET Core 3.2 Preview 3 and fixes for issues created by #314

* Components based on Bootstrap4 for Sections and  TabStrip to increase productivity and promote uniformity in Module UIs

* rolled back change creating an Infrastructure.Interfaces namespace, modified IModule interface to be strongly typed

* modified ITheme interface
2020-04-05 15:31:54 -04:00
02fde9cec3 rolled back change creating an Infrastructure.Interfaces namespace, modified IModule interface to be strongly typed (#343)
* upgrade to .NET Core 3.2 Preview 3 and fixes for issues created by #314

* Components based on Bootstrap4 for Sections and  TabStrip to increase productivity and promote uniformity in Module UIs

* rolled back change creating an Infrastructure.Interfaces namespace, modified IModule interface to be strongly typed
2020-04-05 14:39:08 -04:00
05de65d3a0 Webassembly problem solved (#342) 2020-04-05 13:58:50 -04:00
a2f756729c Use relative path instead 2020-04-05 01:14:12 +03:00
69d89aaaf9 Icon constants (#339) 2020-04-04 14:39:43 -04:00
5af6f7a52d Namespace Fix undo (#340) 2020-04-04 14:06:24 -04:00
d406118d18 Add unit tests 2020-04-04 13:13:40 +03:00
4bc089d2cb Simplify NavigateUrl using UriBuilder 2020-04-04 13:13:26 +03:00
a650f3847d removed connectionstring value 2020-04-03 17:27:04 -04:00
71bd3a8d6a Namespace fix (#335) 2020-04-03 17:18:33 -04:00
6fa2a38f36 Fix regression bugs (#334) 2020-04-03 16:37:02 -04:00
d8b15e7a4e Components based on Bootstrap4 for Sections and TabStrip to increase productivity and promote uniformity in Module UIs (#333)
* upgrade to .NET Core 3.2 Preview 3 and fixes for issues created by #314

* Components based on Bootstrap4 for Sections and  TabStrip to increase productivity and promote uniformity in Module UIs
2020-04-03 15:04:25 -04:00
c38dff5e7c No more magic strings in module definition (#332) 2020-04-03 12:45:27 -04:00
7786cd027b Use string Interpolation for constructing Urls (#324) 2020-04-03 12:44:54 -04:00
2433cc06be Tenant repository bug (#329)
Database Manager bug
2020-04-03 11:36:59 -04:00
7492b018e3 Update README.md 2020-04-02 12:12:20 -04:00
679076cb23 Update README.md 2020-04-02 12:12:02 -04:00
e8efc5e508 upgrade to .NET Core 3.2 Preview 3 and fixes for issues created by #314 (#323) 2020-04-02 12:07:35 -04:00
c2a29831c4 Prevent deleting master tenant (#319)
* Prevent deleting master tenant

* Prevent deletion in APIS level

* Address feedback
2020-04-02 08:08:55 -04:00
0b302c6e26 Startup migration bug (#320)
* Startup migration bug

* ModuleCreator - sql name fix

* Database Manager fixes and improvements

* Database Manager fixes and improvements - removed default password
2020-04-02 08:08:36 -04:00
660dd3289c Update README.md 2020-03-31 12:15:46 -04:00
66ad089088 Refactoring (#314)
* Refactoring

* Refactoring

* Check for a valid email.

* Fixed missing character.

* Moved logic to  the Utilities class.

* Rename template .sql file

* Modified null and empty string check.

* Check for a valid email.

* Fixed missing character.

* Moved logic to  the Utilities class.

* Added Favicon support, Progressive Web App support, page title and url support, and private/public user registration options

* Refactoring

* Refactoring

* Check for a valid email.

* Moved logic to  the Utilities class.

Co-authored-by: Aubrey <aubrey.b@treskcow.tech>
Co-authored-by: MIchael Atwood <matwood@dragonmastery.com>
Co-authored-by: Shaun Walker <shaun.walker@siliqon.com>
2020-03-31 10:21:05 -04:00
c9baa2bb56 Merge pull request #315 from sbwalker/master
Added Favicon support, Progressive Web Apps, page title and urls, and private/public user registration
2020-03-30 20:43:58 -04:00
35f87d25be Added Favicon support, Progressive Web App support, page title and url support, and private/public user registration options 2020-03-30 20:42:43 -04:00
928111dbac Merge pull request #27 from oqtane/master
sync with upstream
2020-03-30 17:00:37 -04:00
65540618d6 Merge pull request #312 from PoisnFang/master
Rename template .sql file
2020-03-30 14:41:53 -04:00
974b8877dc Merge pull request #309 from aubrey-b/email-check
Check for a valid email.
2020-03-30 14:41:38 -04:00
2c348dd49c Merge pull request #306 from chlupac/DatabaseManager
Database Manager
2020-03-30 13:59:19 -04:00
07d17da92a Better script selection criteria 2020-03-30 17:28:06 +02:00
867a0305ba Delete SilentInstall.json 2020-03-29 17:37:00 +02:00
52cb3cb980 Modified null and empty string check. 2020-03-29 09:00:26 -04:00
940cdcb349 Database Manager
done:
+ master.sql as resource
+ implemented incremental database changes also for Master
+ dbUp sql script variables implemented
+ improved database handling and creation code
+ simpified database creation
+ almost all Database and Tenant creation moved to DatabaseManager.cs (rest code marked with TODO)
+ Unattended install of master can be performed by settings in appsettings.json
+ Improved IsInstalled checking
+ Removed DBSchema field from Tenant
+ Default database and site creation moved to Program.Main
2020-03-29 14:45:02 +02:00
00c30dc1cb Rename template .sql file 2020-03-28 00:33:23 -07:00
f8d7732025 Moved logic to the Utilities class. 2020-03-27 13:42:14 -04:00
815572b9a7 Fixed missing character. 2020-03-27 11:29:49 -04:00
9335b18d16 Check for a valid email. 2020-03-27 11:20:36 -04:00
744782df7a Merge pull request #307 from sbwalker/master
Fixed some display issues for mobile rendering
2020-03-25 10:55:00 -04:00
1e688dcf5e Fixed some display issues for mobile rendering 2020-03-25 10:54:34 -04:00
ef21ae64d8 Merge pull request #305 from mikecasas/feature-dialog
Adds an icon for the link/button.
2020-03-25 08:20:54 -04:00
24263025c9 Adds an icon for the link/button. 2020-03-24 21:27:35 -04:00
9c671e6b4c Merge pull request #304 from sbwalker/master
fixes to role management
2020-03-24 16:56:03 -04:00
20e481af3d fixes to role management 2020-03-24 16:56:01 -04:00
32bc4bd13f Merge pull request #26 from oqtane/master
sync
2020-03-24 16:42:46 -04:00
ee59634e23 Merge pull request #303 from sbwalker/master
SQL maanager, Module Creator, module settings enhancements
2020-03-24 14:08:55 -04:00
d9265e127e SQL maanager, Module Creator, module settings enhancements 2020-03-24 14:08:29 -04:00
7ee920bb8b Merge pull request #302 from mikecasas/feature-icon
Added functionality to add icons to the ActionLinks.
2020-03-23 20:20:12 -04:00
ca62560616 Code formatting. 2020-03-23 10:25:12 -04:00
ad031cb375 Added functionality to add icons to the ActionLinks. 2020-03-23 10:24:54 -04:00
5c98d0e536 Merge pull request #25 from oqtane/master
sync with upstream
2020-03-22 09:59:04 -04:00
0988321b37 Update README.md 2020-03-22 09:28:38 -04:00
e4808f9b3c Merge pull request #299 from sbwalker/master
JavaScript interop methods to manage html head elements for title, meta and link
2020-03-20 12:58:23 -04:00
0d11f72083 Merge pull request #298 from chlupac/SiteTemplate
Site repository refactoring
2020-03-20 12:58:09 -04:00
c974b5b78c JavaScript interop methods to manage html head elements for title, meta and link 2020-03-20 12:55:00 -04:00
3077bb6175 Site repository refactoring
Not necessary to build default pages in constructor.
2020-03-20 14:21:41 +01:00
b6e5bcbc69 Merge pull request #295 from sbwalker/master
fixed issues with client-side Blazor
2020-03-19 15:03:21 -04:00
7da2824e50 fixed issues with client-side Blazor 2020-03-19 15:03:11 -04:00
b793c56163 Merge pull request #24 from oqtane/master
Merge pull request #294 from sbwalker/master
2020-03-19 12:11:19 -04:00
3dead185c1 Merge pull request #294 from sbwalker/master
extensibility enhancements for site templates
2020-03-19 12:10:29 -04:00
0c2d1d2449 Merge branch 'master' into master 2020-03-19 12:10:12 -04:00
18a843e74f extensibility enhancements for site templates 2020-03-19 12:07:33 -04:00
ee42db7c39 Merge pull request #292 from chlupac/MagicStrings
Magic Strings - EntityNames
2020-03-18 09:01:16 -04:00
357ede6af9 Merge pull request #293 from sbwalker/master
moved to version 0.0.9 in preparation for MVP release
2020-03-18 09:00:26 -04:00
50bbc7f5b8 moved to version 0.0.9 in preparation for MVP release 2020-03-18 08:59:41 -04:00
65d39974b5 Magic Strings - EntityNames 2020-03-18 09:11:49 +01:00
394 changed files with 24259 additions and 20362 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ Oqtane.Server/appsettings.json
Oqtane.Server/Data/*.mdf
Oqtane.Server/Data/*.ldf
/Oqtane.Server/Properties/PublishProfiles/FolderProfile.pubxml

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 .NET Foundation
Copyright (c) 2018-2020 .NET Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -19,12 +19,13 @@
@code {
private bool _initialized;
private bool _installed;
private PageState PageState { get; set; }
protected override async Task OnParametersSetAsync()
{
var response = await InstallationService.IsInstalled();
_installed = response.Success;
var installation = await InstallationService.IsInstalled();
_installed = installation.Success;
_initialized = true;
}

View File

@ -19,13 +19,13 @@
</div>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private List<Page> _pages;
List<Page> _pages;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override void OnInitialized()
{
Page admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
_pages = PageState.Pages.Where(item => item.ParentId == admin?.PageId).ToList();
}
}

View File

@ -3,7 +3,7 @@
@inject IModuleService ModuleService
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } }
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
protected override async Task OnInitializedAsync()
{
@ -13,6 +13,7 @@
string message = "A Problem Was Encountered Loading Module " + module.ModuleDefinitionName;
AddModuleMessage(message, MessageType.Error);
}
await logger.LogCritical("Error Loading Module {Module}", module);
}
}

View File

@ -1,56 +1,42 @@
@namespace Oqtane.Modules.Admin.Files
@using System.IO
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IFileService FileService
@inject IFolderService FolderService
@if (_folders != null)
{
<div class="container-fluid">
<div class="form-group">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#Upload" role="tab">
Upload Files
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#Download" role="tab">
Download Files
</a>
</li>
</ul>
<div class="tab-content">
<div id="Upload" class="tab-pane fade show active" role="tabpanel">
<TabStrip>
<TabPanel Name="Upload" Heading="Upload Files">
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Upload: </label>
<Label For="upload" HelpText="Upload the file you want">Upload: </Label>
</td>
<td>
<FileManager UploadMultiple="true" ShowFiles="false" FolderId="@_folderId.ToString()" />
<FileManager UploadMultiple="true" ShowFiles="false" FolderId="@_folderId" />
</td>
</tr>
</table>
</div>
<div id="Download" class="tab-pane fade" role="tabpanel">
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
</TabPanel>
<TabPanel Name="Download" Heading="Download Files">
@if (_folders != null)
{
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Url: </label>
<Label For="url" HelpText="Enter the url of the file you wish to download">Url: </Label>
</td>
<td>
<input class="form-control" @bind="@url" />
<input id="url" class="form-control" @bind="@url" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Folder: </label>
<Label For="folder" HelpText="Select the folder to save the file in">Folder: </Label>
</td>
<td>
<select class="form-control" @bind="@_folderId">
<select id="folder" class="form-control" @bind="@_folderId">
<option value="-1">&lt;Select Folder&gt;</option>
@foreach (Folder folder in _folders)
{
@ -60,21 +46,18 @@
</td>
</tr>
</table>
<button type="button" class="btn btn-primary" @onclick="Download">Download</button>
</div>
</div>
</div>
</div>
<br />
<button type="button" class="btn btn-success" @onclick="Download">Download</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
}
</TabPanel>
</TabStrip>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private string url = string.Empty;
private List<Folder> _folders;
private int _folderId = -1;
string url = "";
List<Folder> _folders;
int _folderId = -1;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
@ -88,19 +71,33 @@
private async Task Download()
{
try
if (url == string.Empty || _folderId == -1)
{
if (url != "" && _folderId != -1)
AddModuleMessage("You Must Enter A Url And Select A Folder", MessageType.Warning);
return;
}
var filename = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1);
if (!Constants.UploadableFiles.Split(',')
.Contains(Path.GetExtension(filename).ToLower().Replace(".", "")))
{
AddModuleMessage("File Could Not Be Downloaded From Url Due To Its File Extension", MessageType.Warning);
return ;
}
if (!filename.IsPathOrFileValid())
{
AddModuleMessage("You Must Enter A Url With A Valid File Name", MessageType.Warning);
return;
}
try
{
await FileService.UploadFileAsync(url, _folderId);
await logger.LogInformation("File Downloaded Successfully From Url {Url}", url);
AddModuleMessage("File Downloaded Successfully From Url", MessageType.Success);
}
else
{
AddModuleMessage("You Must Enter A Url And Select A Folder", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading File From Url {Url} {Error}", url, ex.Message);

View File

@ -8,10 +8,10 @@
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Parent: </label>
<Label For="parent" HelpText="Select the parent folder">Parent: </Label>
</td>
<td>
<select class="form-control" @bind="@_parentId">
<select id="parent" class="form-control" @bind="@_parentId">
@if (PageState.QueryString.ContainsKey("id"))
{
<option value="-1">&lt;No Parent&gt;</option>
@ -25,18 +25,16 @@
</tr>
<tr>
<td>
<label class="control-label">Name: </label>
<Label for="name" HelpText="Enter the folder name">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@_name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Permissions: </label>
</td>
<td>
<PermissionGrid EntityName="Folder" PermissionNames="Browse,View,Edit" Permissions="@_permissions" @ref="_permissionGrid" />
<td colspan="2" align="center">
<Label For="permissions" HelpText="Select the permissions you want for the folder">Permissions: </Label>
<PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="Browse,View,Edit" Permissions="@_permissions" @ref="_permissionGrid" />
</td>
</tr>
</table>
@ -58,24 +56,25 @@
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
public override string Title { get { return "Folder Management"; } }
List<Folder> _folders;
int _folderId = -1;
string _name;
int _parentId = -1;
bool _isSystem;
string _permissions = "";
string _createdBy;
DateTime _createdOn;
string _modifiedBy;
DateTime _modifiedOn;
private List<Folder> _folders;
private int _folderId = -1;
private string _name;
private int _parentId = -1;
private bool _isSystem;
private string _permissions = string.Empty;
private string _createdBy;
private DateTime _createdOn;
private string _modifiedBy;
private DateTime _modifiedOn;
#pragma warning disable 649
PermissionGrid _permissionGrid;
private PermissionGrid _permissionGrid;
#pragma warning restore 649
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
public override string Title => "Folder Management";
protected override async Task OnInitializedAsync()
{
try
@ -101,11 +100,7 @@
else
{
_parentId = _folders[0].FolderId;
List<PermissionString> permissionstrings = new List<PermissionString>();
permissionstrings.Add(new PermissionString { PermissionName = PermissionNames.Browse, Permissions = Constants.AdminRole });
permissionstrings.Add(new PermissionString { PermissionName = PermissionNames.View, Permissions = Constants.AdminRole });
permissionstrings.Add(new PermissionString { PermissionName = PermissionNames.Edit, Permissions = Constants.AdminRole });
_permissions = UserSecurity.SetPermissionStrings(permissionstrings);
_permissions = string.Empty;
}
}
catch (Exception ex)
@ -117,9 +112,19 @@
private async Task SaveFolder()
{
try
if (_name == string.Empty || _parentId == -1)
{
if (_name != "" && _parentId != -1)
AddModuleMessage("Folders Must Have A Parent And A Name", MessageType.Warning);
return;
}
if (!_name.IsPathOrFileValid())
{
AddModuleMessage("Folder Name Not Valid.", MessageType.Warning);
return;
}
try
{
Folder folder;
if (_folderId != -1)
@ -132,6 +137,7 @@
}
folder.SiteId = PageState.Site.SiteId;
if (_parentId == -1)
{
folder.ParentId = null;
@ -140,6 +146,7 @@
{
folder.ParentId = _parentId;
}
folder.Name = _name;
folder.IsSystem = _isSystem;
folder.Permissions = _permissionGrid.GetPermissions();
@ -152,13 +159,16 @@
{
folder = await FolderService.AddFolderAsync(folder);
}
if (folder != null)
{
await FolderService.UpdateFolderOrderAsync(folder.SiteId, folder.FolderId, folder.ParentId);
await logger.LogInformation("Folder Saved {Folder}", folder);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage("Folders Must Have A Parent And A Name", MessageType.Warning);
AddModuleMessage("An Error Was Encountered Saving The Folder", MessageType.Error);
}
}
catch (Exception ex)

View File

@ -28,7 +28,7 @@
</table>
<Pager Items="@_files">
<Header>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
<th>Modified</th>
<th>Type</th>
@ -49,17 +49,18 @@
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private List<Folder> _folders;
private int _folderId = -1;
private List<File> _files;
List<Folder> _folders;
int _folderId = -1;
List<File> _files;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnParametersSetAsync()
{
try
{
_folders = await FolderService.GetFoldersAsync(PageState.Site.SiteId);
if (_folderId == -1 && _folders.Count > 0)
{
_folderId = _folders[0].FolderId;

View File

@ -3,29 +3,29 @@
@inject NavigationManager NavigationManager
@inject IJobService JobService
<table class="table table-borderless">
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
<Label For="name" HelpText="Enter the job name">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@_name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Type: </label>
<Label For="type" HelpText="Enter the job type">Type: </Label>
</td>
<td>
<input class="form-control" @bind="@_jobType" />
<input id="type" class="form-control" @bind="@_jobType" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Enabled? </label>
<Label For="enabled" HelpText="Select whether you want the job enabled or not">Enabled? </Label>
</td>
<td>
<select class="form-control" @bind="@_isEnabled">
<select id="enabled" class="form-control" @bind="@_isEnabled">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -33,11 +33,11 @@
</tr>
<tr>
<td>
<label class="control-label">Runs Every: </label>
<Label For="runs-every" HelpText="Select how often you want the job to run">Runs Every: </Label>
</td>
<td>
<input class="form-control" @bind="@_interval" />
<select class="form-control" @bind="@_frequency">
<input id="runs-every" class="form-control" @bind="@_interval" />
<select id="runs-every" class="form-control" @bind="@_frequency">
<option value="m">Minute(s)</option>
<option value="H">Hour(s)</option>
<option value="d">Day(s)</option>
@ -47,55 +47,56 @@
</tr>
<tr>
<td>
<label class="control-label">Starting: </label>
<Label For="starting" HelpText="What time do you want the job to start">Starting: </Label>
</td>
<td>
<input class="form-control" @bind="@_startDate" />
<input id="starting" class="form-control" @bind="@_startDate" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Ending: </label>
<Label For="ending" HelpText="When do you want the job to end">Ending: </Label>
</td>
<td>
<input class="form-control" @bind="@_endDate" />
<input id="ending" class="form-control" @bind="@_endDate" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Retention Log (Items): </label>
<Label For="retention-log" HelpText="What items do you want in the retention log">Retention Log (Items): </Label>
</td>
<td>
<input class="form-control" @bind="@_retentionHistory" />
<input id="retention-log" class="form-control" @bind="@_retentionHistory" />
</td>
</tr>
</table>
</table>
<button type="button" class="btn btn-success" @onclick="SaveJob">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private string _name = string.Empty;
private string _jobType = string.Empty;
private string _isEnabled = "True";
private string _interval = string.Empty;
private string _frequency = string.Empty;
private string _startDate = string.Empty;
private string _endDate = string.Empty;
private string _retentionHistory = "10";
string _name = "";
string _jobType = "";
string _isEnabled = "True";
string _interval = "";
string _frequency = "";
string _startDate = "";
string _endDate = "";
string _retentionHistory = "10";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
private async Task SaveJob()
{
if (_name != "" && !string.IsNullOrEmpty(_jobType) && _frequency != "" && _interval != "" && _retentionHistory != "")
if (_name != string.Empty && !string.IsNullOrEmpty(_jobType) && _frequency != string.Empty && _interval != string.Empty && _retentionHistory != string.Empty)
{
Job job = new Job();
var job = new Job();
job.Name = _name;
job.JobType = _jobType;
job.IsEnabled = Boolean.Parse(_isEnabled);
job.Frequency = _frequency;
job.Interval = int.Parse(_interval);
if (_startDate == "")
if (_startDate == string.Empty)
{
job.StartDate = null;
}
@ -103,7 +104,8 @@
{
job.StartDate = DateTime.Parse(_startDate);
}
if (_endDate == "")
if (_endDate == string.Empty)
{
job.EndDate = null;
}
@ -111,6 +113,7 @@
{
job.EndDate = DateTime.Parse(_endDate);
}
job.RetentionHistory = int.Parse(_retentionHistory);
job.IsStarted = false;
job.IsExecuting = false;

View File

@ -3,29 +3,29 @@
@inject NavigationManager NavigationManager
@inject IJobService JobService
<table class="table table-borderless">
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
<Label For="name" HelpText="Enter the job name">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@_name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Type: </label>
<Label For="type" HelpText="Enter the job type">Type: </Label>
</td>
<td>
<input class="form-control" @bind="@_jobType" />
<input id="type" class="form-control" @bind="@_jobType" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Enabled? </label>
<Label For="enabled" HelpText="Select whether you want the job enabled or not">Enabled? </Label>
</td>
<td>
<select class="form-control" @bind="@_isEnabled">
<select id="enabled" class="form-control" @bind="@_isEnabled">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -33,11 +33,11 @@
</tr>
<tr>
<td>
<label class="control-label">Runs Every: </label>
<Label For="runs-every" HelpText="Select how often you want the job to run">Runs Every: </Label>
</td>
<td>
<input class="form-control" @bind="@_interval" />
<select class="form-control" @bind="@_frequency">
<input id="runs-every" class="form-control" @bind="@_interval" />
<select id="runs-every" class="form-control" @bind="@_frequency">
<option value="m">Minute(s)</option>
<option value="H">Hour(s)</option>
<option value="d">Day(s)</option>
@ -47,44 +47,44 @@
</tr>
<tr>
<td>
<label class="control-label">Starting: </label>
<Label For="starting" HelpText="What time do you want the job to start">Starting: </Label>
</td>
<td>
<input class="form-control" @bind="@_startDate" />
<input id="starting" class="form-control" @bind="@_startDate" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Ending: </label>
<Label For="ending" HelpText="When do you want the job to end">Ending: </Label>
</td>
<td>
<input class="form-control" @bind="@_endDate" />
<input id="ending" class="form-control" @bind="@_endDate" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Retention Log (Items): </label>
<Label For="retention-log" HelpText="What items do you want in the retention log">Retention Log (Items): </Label>
</td>
<td>
<input class="form-control" @bind="@_retentionHistory" />
<input id="retention-log" class="form-control" @bind="@_retentionHistory" />
</td>
</tr>
</table>
</table>
<button type="button" class="btn btn-success" @onclick="SaveJob">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private int _jobId;
private string _name = string.Empty;
private string _jobType = string.Empty;
private string _isEnabled = "True";
private string _interval = string.Empty;
private string _frequency = string.Empty;
private string _startDate = string.Empty;
private string _endDate = string.Empty;
private string _retentionHistory = string.Empty;
int _jobId;
string _name = "";
string _jobType = "";
string _isEnabled = "True";
string _interval = "";
string _frequency = "";
string _startDate = "";
string _endDate = "";
string _retentionHistory = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
@ -99,8 +99,8 @@
_isEnabled = job.IsEnabled.ToString();
_interval = job.Interval.ToString();
_frequency = job.Frequency;
_startDate = (job.StartDate != null) ? job.StartDate.ToString() : "";
_endDate = (job.EndDate != null) ? job.EndDate.ToString() : "";
_startDate = (job.StartDate != null) ? job.StartDate.ToString() : string.Empty;
_endDate = (job.EndDate != null) ? job.EndDate.ToString() : string.Empty;
_retentionHistory = job.RetentionHistory.ToString();
}
}
@ -113,15 +113,16 @@
private async Task SaveJob()
{
if (_name != "" && !string.IsNullOrEmpty(_jobType) && _frequency != "" && _interval != "" && _retentionHistory != "")
if (_name != string.Empty && !string.IsNullOrEmpty(_jobType) && _frequency != string.Empty && _interval != string.Empty && _retentionHistory != string.Empty)
{
Job job = await JobService.GetJobAsync(_jobId);
var job = await JobService.GetJobAsync(_jobId);
job.Name = _name;
job.JobType = _jobType;
job.IsEnabled = Boolean.Parse(_isEnabled);
job.Frequency = _frequency;
job.Interval = int.Parse(_interval);
if (_startDate == "")
if (_startDate == string.Empty)
{
job.StartDate = null;
}
@ -129,7 +130,8 @@
{
job.StartDate = DateTime.Parse(_startDate);
}
if (_endDate == "")
if (_endDate == string.Empty)
{
job.EndDate = null;
}
@ -137,6 +139,7 @@
{
job.EndDate = DateTime.Parse(_endDate);
}
job.RetentionHistory = int.Parse(_retentionHistory);
try

View File

@ -15,14 +15,14 @@ else
<Pager Items="@_jobs">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
<th>Status</th>
<th>Frequency</th>
<th>Next Execution</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.JobId.ToString())" /></td>
@ -47,9 +47,9 @@ else
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<Job> _jobs;
List<Job> _jobs;
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
protected override async Task OnParametersSetAsync()
{
@ -58,7 +58,7 @@ else
private string DisplayStatus(bool isEnabled, bool isExecuting)
{
string status = "";
var status = string.Empty;
if (!isEnabled)
{
status = "Disabled";
@ -81,7 +81,7 @@ else
private string DisplayFrequency(int interval, string frequency)
{
string result = "Every " + interval.ToString() + " ";
var result = "Every " + interval.ToString() + " ";
switch (frequency)
{
case "m":
@ -97,10 +97,12 @@ else
result += "Month";
break;
}
if (interval > 1)
{
result += "s";
}
return result;
}

View File

@ -28,23 +28,25 @@ else
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<JobLog> _jobLogs;
List<JobLog> _jobLogs;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnParametersSetAsync()
{
_jobLogs = await JobLogService.GetJobLogsAsync();
if (PageState.QueryString.ContainsKey("id"))
{
_jobLogs = _jobLogs.Where(item => item.JobId == Int32.Parse(PageState.QueryString["id"])).ToList();
}
_jobLogs = _jobLogs.OrderByDescending(item => item.JobLogId).ToList();
}
private string DisplayStatus(bool isExecuting, bool? succeeded)
{
string status = "";
var status = string.Empty;
if (isExecuting)
{
status = "Executing";
@ -60,6 +62,7 @@ else
status = "Failed";
}
}
return status;
}
}

View File

@ -1,11 +1,10 @@
@namespace Oqtane.Modules.Admin.Login
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IJSRuntime JsRuntime
@inject IUserService UserService
@inject IServiceProvider ServiceProvider
@if (_message != "")
@if (_message != string.Empty)
{
<ModuleMessage Message="@_message" Type="@_type" />
}
@ -14,7 +13,7 @@
<text>...</text>
</Authorizing>
<Authorized>
You are already logged in
<ModuleMessage Message="You Are Already Logged In" Type="MessageType.Info" />
</Authorized>
<NotAuthorized>
<div class="container">
@ -41,14 +40,14 @@
</AuthorizeView>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } }
private string _returnUrl = string.Empty;
private string _message = string.Empty;
private MessageType _type = MessageType.Info;
private string _username = string.Empty;
private string _password = string.Empty;
private bool _remember = false;
string _returnUrl = "";
string _message = "";
MessageType _type = MessageType.Info;
string _username = "";
string _password = "";
bool _remember = false;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
protected override async Task OnInitializedAsync()
{
@ -56,13 +55,15 @@
{
_returnUrl = PageState.QueryString["returnurl"];
}
if (PageState.QueryString.ContainsKey("name"))
{
_username = PageState.QueryString["name"];
}
if (PageState.QueryString.ContainsKey("token"))
{
User user = new User();
var user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = _username;
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
@ -81,23 +82,23 @@
private async Task Login()
{
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
if (authstateprovider == null)
if (PageState.Runtime == Runtime.Server)
{
// server-side Blazor
User user = new User();
var user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = _username;
user.Password = _password;
user = await UserService.LoginUserAsync(user, false, false);
if (user.IsAuthenticated)
{
await logger.LogInformation("Login Successful For Username {Username}", _username);
// complete the login on the server so that the cookies are set correctly on SignalR
var interop = new Interop(JsRuntime);
var interop = new Interop(JSRuntime);
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
var fields = new { __RequestVerificationToken = antiforgerytoken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
await interop.SubmitForm("/pages/login/", fields);
await interop.SubmitForm($"/{PageState.Alias.AliasId}/pages/login/", fields);
}
else
{
@ -108,7 +109,7 @@
else
{
// client-side Blazor
User user = new User();
var user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = _username;
user.Password = _password;
@ -116,6 +117,7 @@
if (user.IsAuthenticated)
{
await logger.LogInformation("Login Successful For Username {Username}", _username);
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
authstateprovider.NotifyAuthenticationChanged();
NavigationManager.NavigateTo(NavigateUrl(_returnUrl, "reload"));
}
@ -134,9 +136,9 @@
private async Task Forgot()
{
if (_username != "")
if (_username != string.Empty)
{
User user = await UserService.GetUserAsync(_username, PageState.Site.SiteId);
var user = await UserService.GetUserAsync(_username, PageState.Site.SiteId);
if (user != null)
{
await UserService.ForgotPasswordAsync(user);
@ -152,6 +154,7 @@
{
_message = "Please Enter The Username Related To Your Account And Then Select The Forgot Password Option Again";
}
StateHasChanged();
}
}
}

View File

@ -10,156 +10,156 @@
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Date/Time: </label>
<Label For="dateTime" HelpText="The date and time of this log">Date/Time: </Label>
</td>
<td>
<input class="form-control" @bind="@_logDate" disabled />
<input id="dateTime" class="form-control" @bind="@_logDate" readonly />
</td>
</tr>
<tr>
<td>
<label class="control-label">Level: </label>
<Label For="level" HelpText="The level of this log">Level: </Label>
</td>
<td>
<input class="form-control" @bind="@_level" disabled />
<input id="level" class="form-control" @bind="@_level" readonly />
</td>
</tr>
<tr>
<td>
<label class="control-label">Feature: </label>
<Label For="feature" HelpText="The feature that was affected">Feature: </Label>
</td>
<td>
<input class="form-control" @bind="@_feature" disabled />
<input id="feature" class="form-control" @bind="@_feature" readonly />
</td>
</tr>
<tr>
<td>
<label class="control-label">Function: </label>
<Label For="function" HelpText="The function that was performed">Function: </Label>
</td>
<td>
<input class="form-control" @bind="@_function" disabled />
<input id="function" class="form-control" @bind="@_function" readonly />
</td>
</tr>
<tr>
<td>
<label class="control-label">Category: </label>
<Label For="category" HelpText="The categories that were affected">Category: </Label>
</td>
<td>
<input class="form-control" @bind="@_category" disabled />
<input id="category" class="form-control" @bind="@_category" readonly />
</td>
</tr>
@if (_pageName != "")
@if (_pageName != string.Empty)
{
<tr>
<td>
<label class="control-label">Page: </label>
<Label For="page" HelpText="The page that was affected">Page: </Label>
</td>
<td>
<input class="form-control" @bind="@_pageName" disabled />
<input id="page" class="form-control" @bind="@_pageName" readonly />
</td>
</tr>
}
@if (_moduleTitle != "")
@if (_moduleTitle != string.Empty)
{
<tr>
<td>
<label class="control-label">Module: </label>
<Label For="module" HelpText="The module that was affected">Module: </Label>
</td>
<td>
<input class="form-control" @bind="@_moduleTitle" disabled />
<input id="module" class="form-control" @bind="@_moduleTitle" readonly />
</td>
</tr>
}
@if (_username != "")
@if (_username != string.Empty)
{
<tr>
<td>
<label class="control-label">User: </label>
<Label For="user" HelpText="The user that caused this log">User: </Label>
</td>
<td>
<input class="form-control" @bind="@_username" disabled />
<input id="user" class="form-control" @bind="@_username" readonly />
</td>
</tr>
}
<tr>
<td>
<label class="control-label">Url: </label>
<Label For="url" HelpText="The url the log comes from">Url: </Label>
</td>
<td>
<input class="form-control" @bind="@_url" disabled />
<input id="url" class="form-control" @bind="@_url" readonly />
</td>
</tr>
<tr>
<td>
<label class="control-label">Template: </label>
<Label For="template" HelpText="What the log is about">Template: </Label>
</td>
<td>
<input class="form-control" @bind="@_template" disabled />
<input id="template" class="form-control" @bind="@_template" readonly />
</td>
</tr>
<tr>
<td>
<label class="control-label">Message: </label>
<Label For="message" HelpText="The message that the system generated"class="control-label">Message: </Label>
</td>
<td>
<textarea class="form-control" @bind="@_message" rows="5" disabled></textarea>
<textarea id="message" class="form-control" @bind="@_message" rows="5" readonly></textarea>
</td>
</tr>
@if (!string.IsNullOrEmpty(_exception))
{
<tr>
<td>
<label class="control-label">Exception: </label>
<Label For="exception" HelpText="The exceptions generated by the system">Exception: </Label>
</td>
<td>
<textarea class="form-control" @bind="@_exception" rows="5" disabled></textarea>
<textarea id="exception" class="form-control" @bind="@_exception" rows="5" readonly></textarea>
</td>
</tr>
}
<tr>
<td>
<label class="control-label">Properties: </label>
<Label For="properties" HelpText="The properties that were affected">Properties: </Label>
</td>
<td>
<textarea class="form-control" @bind="@_properties" rows="5" disabled></textarea>
<textarea id="properties" class="form-control" @bind="@_properties" rows="5" readonly></textarea>
</td>
</tr>
<tr>
<td>
<label class="control-label">Server: </label>
<Label For="server" HelpText="The server that was affected">Server: </Label>
</td>
<td>
<input class="form-control" @bind="@_server" disabled />
<input id="server" class="form-control" @bind="@_server" readonly />
</td>
</tr>
</table>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private int _logId;
private string _logDate = string.Empty;
private string _level = string.Empty;
private string _feature = string.Empty;
private string _function = string.Empty;
private string _category = string.Empty;
private string _pageName = string.Empty;
private string _moduleTitle = string.Empty;
private string _username = string.Empty;
private string _url = string.Empty;
private string _template = string.Empty;
private string _message = string.Empty;
private string _exception = string.Empty;
private string _properties = string.Empty;
private string _server = string.Empty;
int _logId;
string _logDate = "";
string _level = "";
string _feature = "";
string _function = "";
string _category = "";
string _pageName = "";
string _moduleTitle = "";
string _username = "";
string _url = "";
string _template = "";
string _message = "";
string _exception = "";
string _properties = "";
string _server = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
try
{
_logId = Int32.Parse(PageState.QueryString["id"]);
Log log = await LogService.GetLogAsync(_logId);
var log = await LogService.GetLogAsync(_logId);
if (log != null)
{
_logDate = log.LogDate.ToString(CultureInfo.CurrentCulture);
@ -167,30 +167,34 @@
_feature = log.Feature;
_function = log.Function;
_category = log.Category;
if (log.PageId != null)
{
Page page = await PageService.GetPageAsync(log.PageId.Value);
var page = await PageService.GetPageAsync(log.PageId.Value);
if (page != null)
{
_pageName = page.Name;
}
}
if (log.PageId != null && log.ModuleId != null)
{
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(log.PageId.Value, log.ModuleId.Value);
var pagemodule = await PageModuleService.GetPageModuleAsync(log.PageId.Value, log.ModuleId.Value);
if (pagemodule != null)
{
_moduleTitle = pagemodule.Title;
}
}
if (log.UserId != null)
{
User user = await UserService.GetUserAsync(log.UserId.Value, PageState.Site.SiteId);
var user = await UserService.GetUserAsync(log.UserId.Value, PageState.Site.SiteId);
if (user != null)
{
_username = user.Username;
}
}
_url = log.Url;
_template = log.MessageTemplate;
_message = log.Message;

View File

@ -49,7 +49,7 @@ else
{
<Pager Items="@_logs">
<Header>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Date</th>
<th>Level</th>
<th>Feature</th>
@ -71,12 +71,12 @@ else
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private string _level = "-";
private string _function = "-";
private string _rows = "10";
private List<Log> _logs;
string _level = "-";
string _function = "-";
string _rows = "10";
List<Log> _logs;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
@ -139,12 +139,12 @@ else
private async Task GetLogs()
{
_logs = await LogService.GetLogsAsync(PageState.Site.SiteId, ((_level == "-") ? "" : _level), ((_function == "-") ? "" : _function), int.Parse(_rows));
_logs = await LogService.GetLogsAsync(PageState.Site.SiteId, ((_level == "-") ? string.Empty : _level), ((_function == "-") ? string.Empty : _function), int.Parse(_rows));
}
private string GetClass(string function)
{
string classname = "";
string classname = string.Empty;
switch (function)
{
case "Create":
@ -163,7 +163,7 @@ else
classname = "table-secondary";
break;
default:
classname = "";
classname = string.Empty;
break;
}
return classname;

View File

@ -0,0 +1,124 @@
@namespace Oqtane.Modules.Admin.ModuleCreator
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IModuleDefinitionService ModuleDefinitionService
@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))
{
<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>
@code {
private string _owner = string.Empty;
private string _module = string.Empty;
private string _description = string.Empty;
private string _template = "-";
private string _location = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override void OnInitialized()
{
AddModuleMessage("Please Note That Once You Select The Create Module Button The Application Must Restart In Order To Complete The Process. If You Create An External Module You Will Need To Compile The Source Code In Order To Make It Functional.", MessageType.Info);
}
private async Task CreateModule()
{
try
{
if (!string.IsNullOrEmpty(_owner) && !string.IsNullOrEmpty(_module) && _template != "-")
{
var moduleDefinition = new ModuleDefinition { Owner = _owner.Replace(" ", ""), Name = _module.Replace(" ", ""), Description = _description, Template = _template };
await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition, ModuleState.ModuleId);
}
else
{
AddModuleMessage("You Must Provide An Owner, Module Name, And Template", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Creating Module");
}
}
private async void TemplateChanged(ChangeEventArgs e)
{
try
{
_location = string.Empty;
_template = (string)e.Value;
if (_template != "-")
{
Dictionary<string, string> systeminfo = await SystemService.GetSystemInfoAsync();
if (systeminfo != null)
{
string[] path = systeminfo["serverpath"].Split('\\');
if (_template == "internal")
{
_location = string.Join("\\", path, 0, path.Length - 1) + "\\Oqtane.Client\\Modules\\" + _owner + "." + _module + "s";
}
else
{
_location = string.Join("\\", path, 0, path.Length - 2) + "\\" + _owner + "." + _module + "s";
}
}
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Getting System Info {Error}", ex.Message);
AddModuleMessage("Error Getting System Info", MessageType.Error);
}
}
}

View File

@ -0,0 +1,15 @@
using Oqtane.Models;
namespace Oqtane.Modules.Admin.ModuleCreator
{
public class ModuleInfo : IModule
{
public ModuleDefinition ModuleDefinition => new ModuleDefinition
{
Name = "Module Creator",
Description = "Enables software developers to quickly create modules by automating many of the initial module creation tasks",
Version = "1.0.0",
Categories = "Developer"
};
}
}

View File

@ -5,54 +5,60 @@
@inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Module: </label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Modules" />
</td>
</tr>
</table>
@if (_packages != null)
{
<hr class="app-rule" />
<div class="mx-auto text-center"><h2>Available Modules</h2></div>
<TabStrip>
@if (_packages.Count > 0)
{
<TabPanel Name="Download">
<ModuleMessage Type="MessageType.Info" Message="Download one or more modules from the list below. Once you are ready click Install to complete the installation."></ModuleMessage>
<Pager Items="@_packages">
<Header>
<th>Name</th>
<th>Version</th>
<th></th>
<th style="width: 1px"></th>
</Header>
<Row>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadModule(context.PackageId, context.Version))>Download Module</button>
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadModule(context.PackageId, context.Version))>Download</button>
</td>
</Row>
</Pager>
</TabPanel>
}
<TabPanel Name="Upload">
<table class="table table-borderless">
<tr>
<td>
<Label HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation.">Module: </Label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Modules" UploadMultiple="true" />
</td>
</tr>
</table>
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="InstallModules">Install</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
<button type="button" class="btn btn-success" @onclick="InstallModules">Install</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<Package> _packages;
List<Package> _packages;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
try
{
List<ModuleDefinition> moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
_packages = await PackageService.GetPackagesAsync("module");
foreach(Package package in _packages.ToArray())
foreach (Package package in _packages.ToArray())
{
if (moduledefinitions.Exists(item => Utilities.GetTypeName(item.ModuleDefinitionName) == package.PackageId))
{
@ -71,8 +77,10 @@
{
try
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
@ -80,18 +88,18 @@
}
}
private async Task DownloadModule(string moduledefinitionname, string version)
private async Task DownloadModule(string packageid, string version)
{
try
{
await PackageService.DownloadPackageAsync(moduledefinitionname, version, "Modules");
await logger.LogInformation("Module {ModuleDefinitionName} {Version} Downloaded Successfully", moduledefinitionname, version);
AddModuleMessage("Module Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success);
await PackageService.DownloadPackageAsync(packageid, version, "Modules");
await logger.LogInformation("Module {ModuleDefinitionName} {Version} Downloaded Successfully", packageid, version);
AddModuleMessage("Modules Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version}", moduledefinitionname, version);
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version}", packageid, version);
AddModuleMessage("Error Downloading Module", MessageType.Error);
}
}

View File

@ -3,54 +3,142 @@
@inject IModuleDefinitionService ModuleDefinitionService
@inject NavigationManager NavigationManager
<table class="table table-borderless">
<TabStrip>
<TabPanel Name="Definition">
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
<Label For="name" HelpText="The name of the module">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@_name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Permissions: </label>
<Label For="description" HelpText="The description of the module">Description: </Label>
</td>
<td>
<PermissionGrid EntityName="ModuleDefinition" PermissionNames=PermissionNames.Utilize Permissions="@_permissions" @ref="_permissionGrid" />
<textarea id="description" class="form-control" @bind="@_description" rows="2"></textarea>
</td>
</tr>
</table>
<tr>
<td>
<Label For="categories" HelpText="Comma delimited list of module categories">Categories: </Label>
</td>
<td>
<input id="categories" class="form-control" @bind="@_categories" />
</td>
</tr>
</table>
<Section Name="Information">
<table class="table table-borderless">
<tr>
<td>
<Label For="moduledefinitionname" HelpText="The internal name of the module">Internal Name: </Label>
</td>
<td>
<input id="moduledefinitionname" class="form-control" @bind="@_moduledefinitionname" disabled />
</td>
</tr>
<tr>
<td>
<Label For="version" HelpText="The version of the module">Version: </Label>
</td>
<td>
<input id="version" class="form-control" @bind="@_version" disabled />
</td>
</tr>
<tr>
<td>
<Label For="owner" HelpText="The owner or creator of the module">Owner: </Label>
</td>
<td>
<input id="owner" class="form-control" @bind="@_owner" disabled />
</td>
</tr>
<tr>
<td>
<Label For="url" HelpText="The reference url of the module">Reference Url: </Label>
</td>
<td>
<input id="url" class="form-control" @bind="@_url" disabled />
</td>
</tr>
<tr>
<td>
<Label For="contact" HelpText="The contact for the module">Contact: </Label>
</td>
<td>
<input id="contact" class="form-control" @bind="@_contact" disabled />
</td>
</tr>
<tr>
<td>
<Label For="license" HelpText="The license of the module">License: </Label>
</td>
<td>
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
</td>
</tr>
</table>
</Section>
</TabPanel>
<TabPanel Name="Permissions">
<table class="table table-borderless">
<tr>
<td>
<PermissionGrid EntityName="@EntityNames.ModuleDefinition" PermissionNames="@PermissionNames.Utilize" Permissions="@_permissions" @ref="_permissionGrid" />
</td>
</tr>
</table>
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<br /><br />
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
int _moduleDefinitionId;
string _name;
string _permissions;
string _createdby;
DateTime _createdon;
string _modifiedby;
DateTime _modifiedon;
private int _moduleDefinitionId;
private string _name;
private string _version;
private string _categories;
private string _moduledefinitionname = "";
private string _description = "";
private string _owner = "";
private string _url = "";
private string _contact = "";
private string _license = "";
private string _permissions;
private string _createdby;
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
#pragma warning disable 649
PermissionGrid _permissionGrid;
private PermissionGrid _permissionGrid;
#pragma warning restore 649
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
try
{
_moduleDefinitionId = Int32.Parse(PageState.QueryString["id"]);
ModuleDefinition moduleDefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
var moduleDefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
if (moduleDefinition != null)
{
_name = moduleDefinition.Name;
_version = moduleDefinition.Version;
_categories = moduleDefinition.Categories;
_moduledefinitionname = moduleDefinition.ModuleDefinitionName;
_description = moduleDefinition.Description;
_owner = moduleDefinition.Owner;
_url = moduleDefinition.Url;
_contact = moduleDefinition.Contact;
_license = moduleDefinition.License;
_permissions = moduleDefinition.Permissions;
_createdby = moduleDefinition.CreatedBy;
_createdon = moduleDefinition.CreatedOn;
@ -69,7 +157,19 @@
{
try
{
ModuleDefinition moduledefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
var moduledefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
if (moduledefinition.Name != _name)
{
moduledefinition.Name = _name;
}
if (moduledefinition.Description != _description)
{
moduledefinition.Description = _description;
}
if (moduledefinition.Categories != _categories)
{
moduledefinition.Categories = _categories;
}
moduledefinition.Permissions = _permissionGrid.GetPermissions();
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);

View File

@ -14,11 +14,11 @@ else
<Pager Items="@_moduleDefinitions">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
<th>Version</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" /></td>
@ -41,10 +41,10 @@ else
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<ModuleDefinition> _moduleDefinitions;
private List<Package> _packages;
List<ModuleDefinition> _moduleDefinitions;
List<Package> _packages;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
@ -54,20 +54,27 @@ else
_packages = await PackageService.GetPackagesAsync("module");
}
catch (Exception ex)
{
if (_moduleDefinitions == null)
{
await logger.LogError(ex, "Error Loading Modules {Error}", ex.Message);
AddModuleMessage("Error Loading Modules", MessageType.Error);
}
}
}
private bool UpgradeAvailable(string moduledefinitionname, string version)
{
bool upgradeavailable = false;
Package package = _packages.Where(item => item.PackageId == Utilities.GetTypeName(moduledefinitionname)).FirstOrDefault();
var upgradeavailable = false;
if (_packages != null)
{
var package = _packages.Where(item => item.PackageId == Utilities.GetTypeName(moduledefinitionname)).FirstOrDefault();
if (package != null)
{
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
}
}
return upgradeavailable;
}
@ -76,9 +83,11 @@ else
try
{
await PackageService.DownloadPackageAsync(moduledefinitionname, version, "Modules");
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", moduledefinitionname, version);
NavigationManager.NavigateTo(NavigateUrl());
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
}
catch (Exception ex)
{
@ -91,9 +100,10 @@ else
{
try
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await ModuleDefinitionService.DeleteModuleDefinitionAsync(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId);
await logger.LogInformation("Module Deleted {ModuleDefinition}", moduleDefinition);
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{

View File

@ -7,10 +7,10 @@
<tbody>
<tr>
<td>
<label class="control-label">Content: </label>
<Label For="content" HelpText="Enter the module content">Content: </Label>
</td>
<td>
<textarea class="form-control" @bind="@_content" rows="5"></textarea>
<textarea id="content" class="form-control" @bind="@_content" rows="5"></textarea>
</td>
</tr>
</tbody>
@ -20,10 +20,11 @@
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
public override string Title { get { return "Export Module"; } }
private string _content = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
public override string Title => "Export Module";
string _content = "";
private async Task ExportModule()
{

View File

@ -7,10 +7,10 @@
<tbody>
<tr>
<td>
<label for="Title" class="control-label">Content: </label>
<Label For="content" HelpText="Enter the module content">Content: </Label>
</td>
<td>
<textarea class="form-control" @bind="@_content" rows="5"></textarea>
<textarea id="content" class="form-control" @bind="@_content" rows="5"></textarea>
</td>
</tr>
</tbody>
@ -20,15 +20,14 @@
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
public override string Title { get { return "Import Module"; } }
string _content = "";
private string _content = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
public override string Title => "Import Module";
private async Task ImportModule()
{
if (_content != "")
if (_content != string.Empty)
{
try
{

View File

@ -5,117 +5,170 @@
@inject IModuleService ModuleService
@inject IPageModuleService PageModuleService
<table class="table table-borderless">
<tbody>
<TabStrip>
<TabPanel Name="Settings" Heading="Module Settings">
@if (_containers != null)
{
<table class="table table-borderless">
<tr>
<td>
<label for="Title" class="control-label">Title: </label>
<Label For="title" HelpText="Enter the title of the module">Title: </Label>
</td>
<td>
<input type="text" name="Title" class="form-control" @bind="@_title" />
<input id="title" type="text" name="Title" class="form-control" @bind="@_title" />
</td>
</tr>
<tr>
<td>
<label for="Container" class="control-label">Container: </label>
<Label For="container" HelpText="Select the module's container">Container: </Label>
</td>
<td>
<select class="form-control" @bind="@_containerType">
<option value="">&lt;Select Container&gt;</option>
@foreach (KeyValuePair<string, string> container in _containers)
<select id="container" class="form-control" @bind="@_containerType">
<option value="-">&lt;Inherit From Page Or Site&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.Key">@container.Value</option>
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Permissions: </label>
<Label For="allpages" HelpText="Indicate if this module should be displayed on all pages">Display On All Pages? </Label>
</td>
<td>
<PermissionGrid EntityName="Module" PermissionNames="@_permissionNames" Permissions="@_permissions" @ref="_permissionGrid" />
<select id="allpages" class="form-control" @bind="@_allPages">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Page" class="control-label">Page: </label>
<Label For="page" HelpText="The page that the module is on">Page: </Label>
</td>
<td>
<select class="form-control" @bind="@_pageId">
<select id="page" class="form-control" @bind="@_pageId">
@foreach (Page p in PageState.Pages)
{
<option value="@p.PageId">@p.Name</option>
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
}
}
</select>
</td>
</tr>
</tbody>
</table>
@DynamicComponent
</table>
}
</TabPanel>
<TabPanel Name="Permissions">
@if (_permissions != null)
{
<table class="table table-borderless">
<tr>
<td>
<PermissionGrid EntityName="@EntityNames.Module" PermissionNames="@_permissionNames" Permissions="@_permissions" @ref="_permissionGrid" />
</td>
</tr>
</table>
}
</TabPanel>
@if (_settingsModuleType != null)
{
<TabPanel Name="ModuleSettings" Heading="@_settingstitle">
@DynamicComponent
</TabPanel>
}
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SaveModule">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Edit; } }
public override string Title { get { return "Module Settings"; } }
private List<ThemeControl> _containers = new List<ThemeControl>();
private string _title;
private string _containerType;
private string _allPages = "false";
private string _permissionNames = "";
private string _permissions = null;
private string _pageId;
private PermissionGrid _permissionGrid;
private Type _settingsModuleType;
private string _settingstitle = "Other Settings";
private object _settings;
Dictionary<string, string> _containers = new Dictionary<string, string>();
string _title;
string _containerType;
string _permissionNames = "";
string _permissions;
string _pageId;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
public override string Title => "Module Settings";
#pragma warning disable 649
PermissionGrid _permissionGrid;
#pragma warning restore 649
RenderFragment DynamicComponent { get; set; }
object _settings;
private RenderFragment DynamicComponent { get; set; }
protected override async Task OnInitializedAsync()
{
_title = ModuleState.Title;
_containers = ThemeService.GetContainerTypes(await ThemeService.GetThemesAsync());
_containers = ThemeService.GetContainerControls(await ThemeService.GetThemesAsync(), PageState.Page.ThemeType);
_containerType = ModuleState.ContainerType;
if (!string.IsNullOrEmpty(PageState.Page.DefaultContainerType) && _containerType == PageState.Page.DefaultContainerType)
{
_containerType = "-";
}
if (_containerType == PageState.Site.DefaultContainerType)
{
_containerType = "-";
}
_allPages = ModuleState.AllPages.ToString();
_permissions = ModuleState.Permissions;
_permissionNames = ModuleState.ModuleDefinition.PermissionNames;
_pageId = ModuleState.PageId.ToString();
_settingsModuleType = Type.GetType(ModuleState.ModuleType);
if (_settingsModuleType != null)
{
var moduleobject = Activator.CreateInstance(_settingsModuleType) as IModuleControl;
_settingstitle = moduleobject.Title;
if (string.IsNullOrEmpty(_settingstitle))
{
_settingstitle = "Other Settings";
}
DynamicComponent = builder =>
{
Type moduleType = Type.GetType(ModuleState.ModuleType);
if (moduleType != null)
{
builder.OpenComponent(0, moduleType);
builder.AddComponentReferenceCapture(1, inst => { _settings = Convert.ChangeType(inst, moduleType); });
builder.OpenComponent(0, _settingsModuleType);
builder.AddComponentReferenceCapture(1, inst => { _settings = Convert.ChangeType(inst, _settingsModuleType); });
builder.CloseComponent();
}
};
}
}
private async Task SaveModule()
{
Module module = ModuleState;
module.Permissions = _permissionGrid.GetPermissions();
await ModuleService.UpdateModuleAsync(module);
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
pagemodule.PageId = int.Parse(_pageId);
pagemodule.Title = _title;
pagemodule.ContainerType = _containerType;
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
{
pagemodule.ContainerType = string.Empty;
}
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
{
pagemodule.ContainerType = string.Empty;
}
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
Type moduleType = Type.GetType(ModuleState.ModuleType);
var module = ModuleState;
module.AllPages = bool.Parse(_allPages);
module.Permissions = _permissionGrid.GetPermissions();
await ModuleService.UpdateModuleAsync(module);
if (_settingsModuleType != null)
{
var moduleType = Type.GetType(ModuleState.ModuleType);
if (moduleType != null)
{
moduleType.GetMethod("UpdateSettings")?.Invoke(_settings, null); // method must be public in settings component
}
}
NavigationManager.NavigateTo(NavigateUrl());
}

View File

@ -4,31 +4,25 @@
@inject IPageService PageService
@inject IThemeService ThemeService
@if (_themeList != null)
{
<TabStrip>
<TabPanel Name="Settings">
@if (_themeList != null)
{
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
<Label For="Name" HelpText="Enter the page name">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@_name" />
<input id="Name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Path: </label>
<Label For="Parent" HelpText="Select the parent for the page in the site hierarchy">Parent: </Label>
</td>
<td>
<input class="form-control" @bind="@_path" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Parent: </label>
</td>
<td>
<select class="form-control" @onchange="(e => ParentChanged(e))">
<select id="Parent" class="form-control" @onchange="(e => ParentChanged(e))">
<option value="-1">&lt;Site Root&gt;</option>
@foreach (Page page in _pageList)
{
@ -39,10 +33,10 @@
</tr>
<tr>
<td>
<label for="Name" class="control-label">Insert: </label>
<Label For="Insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages">Insert: </Label>
</td>
<td>
<select class="form-control" @bind="@_insert">
<select id="Insert" class="form-control" @bind="@_insert">
<option value="<<">At Beginning</option>
@if (_children != null && _children.Count > 0)
{
@ -65,10 +59,10 @@
</tr>
<tr>
<td>
<label for="Name" class="control-label">Navigation? </label>
<Label For="Navigation" HelpText="Select whether the page is part of the site navigation or hidden">Navigation? </Label>
</td>
<td>
<select class="form-control" @bind="@_isnavigation">
<select id="Navigation" class="form-control" @bind="@_isnavigation">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -76,21 +70,104 @@
</tr>
<tr>
<td>
<label for="Name" class="control-label">Personalizable? </label>
<Label For="Path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used.">Url Path: </Label>
</td>
<td>
<select class="form-control" @bind="@_ispersonalizable">
<option value="True">Yes</option>
<option value="False">No</option>
<input id="Path" class="form-control" @bind="@_path" />
</td>
</tr>
<tr>
<td>
<Label For="Url" HelpText="Optionally enter a url which this page should redirect to when a user navigates to it">Redirect: </Label>
</td>
<td>
<input id="Url" class="form-control" @bind="@_url" />
</td>
</tr>
</table>
<Section Name="Appearance">
<table class="table table-borderless">
<tr>
<td>
<Label For="Title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used.">Title: </Label>
</td>
<td>
<input id="Title" class="form-control" @bind="@_title" />
</td>
</tr>
<tr>
<td>
<Label For="Theme" HelpText="Select the theme for this page">Theme: </Label>
</td>
<td>
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;Inherit From Site&gt;</option>
@foreach (var theme in _themes)
{
if (theme.TypeName == _themetype)
{
<option value="@theme.TypeName" selected>@theme.Name</option>
}
else
{
<option value="@theme.TypeName">@theme.Name</option>
}
}
</select>
</td>
</tr>
@if (_layouts.Count > 0)
{
<tr>
<td>
<Label For="Layout" HelpText="Select a layout for the page (if the selected theme supports it)">Layout: </Label>
</td>
<td>
<select id="Layout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;Inherit From Site&gt;</option>
@foreach (var layout in _layouts)
{
if (layout.TypeName == _layouttype)
{
<option value="@(layout.TypeName)" selected>@(layout.Name)</option>
}
else
{
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the page">Default Container: </Label>
</td>
<td>
<select id="defaultContainer" class="form-control" @bind="@_containertype">
<option value="-">&lt;Inherit From Site&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Mode? </label>
<Label For="Icon" HelpText="Optionally provide an icon for this page which will be displayed in the site navigation">Icon: </Label>
</td>
<td>
<select class="form-control" @bind="@_mode">
<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>
@ -98,76 +175,57 @@
</tr>
<tr>
<td>
<label for="Name" class="control-label">Theme: </label>
<Label For="Personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content">Personalizable? </Label>
</td>
<td>
<select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in _themes)
{
<option value="@item.Key">@item.Value</option>
}
<select id="Personalizable" class="form-control" @bind="@_ispersonalizable">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Layout: </label>
</td>
<td>
<select class="form-control" @bind="@_layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Icon: </label>
</td>
<td>
<input class="form-control" @bind="@_icon" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Permissions: </label>
</td>
<td>
<PermissionGrid EntityName="Page" Permissions="@_permissions" @ref="_permissionGrid" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SavePage">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
</Section>
}
</TabPanel>
<TabPanel Name="Permissions">
<table class="table table-borderless">
<tr>
<td>
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
</td>
</tr>
</table>
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SavePage">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<Page> _pageList;
private string _name;
private string _title;
private string _path = string.Empty;
private string _parentid;
private string _insert = ">>";
private List<Page> _children;
private int _childid = -1;
private string _isnavigation = "True";
private string _url;
private string _ispersonalizable = "False";
private string _mode = "view";
private string _themetype = "-";
private string _layouttype = "-";
private string _containertype = "-";
private string _icon = string.Empty;
private string _permissions = string.Empty;
private PermissionGrid _permissionGrid;
Dictionary<string, string> _themes = new Dictionary<string, string>();
Dictionary<string, string> _panelayouts = new Dictionary<string, string>();
List<Theme> _themeList;
List<Page> _pageList;
string _name;
string _path = "";
string _parentid;
string _insert = ">>";
List<Page> _children;
int _childid = -1;
string _isnavigation = "True";
string _ispersonalizable = "False";
string _mode = "view";
string _themetype = "";
string _layouttype = "";
string _icon = "";
string _permissions = "";
PermissionGrid _permissionGrid;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
@ -177,16 +235,8 @@
_pageList = PageState.Pages;
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
_themes = ThemeService.GetThemeTypes(_themeList);
_themetype = PageState.Site.DefaultThemeType;
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_layouttype = PageState.Site.DefaultLayoutType;
List<PermissionString> permissionstrings = new List<PermissionString>();
permissionstrings.Add(new PermissionString { PermissionName = PermissionNames.View, Permissions = Constants.AdminRole });
permissionstrings.Add(new PermissionString { PermissionName = PermissionNames.Edit, Permissions = Constants.AdminRole });
_permissions = UserSecurity.SetPermissionStrings(permissionstrings);
_themes = ThemeService.GetThemeControls(_themeList);
_permissions = string.Empty;
}
catch (Exception ex)
{
@ -200,13 +250,26 @@
try
{
_parentid = (string)e.Value;
_children = new List<Page>();
if (_parentid == "-1")
{
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
_children.Add(p);
}
}
}
else
{
_children = PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)).ToList();
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
_children.Add(p);
}
}
}
StateHasChanged();
}
@ -222,14 +285,18 @@
try
{
_themetype = (string)e.Value;
if (_themetype != "")
if (_themetype != "-")
{
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_panelayouts = new Dictionary<string, string>();
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containertype = "-";
StateHasChanged();
}
catch (Exception ex)
@ -244,19 +311,22 @@
Page page = null;
try
{
if (_name != "" && !string.IsNullOrEmpty(_themetype) && (_panelayouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)))
if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && (_layouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)))
{
page = new Page();
page.SiteId = PageState.Page.SiteId;
page.Name = _name;
page.Title = _title;
if (_path == "")
{
_path = _name;
}
if (_path.Contains("/"))
{
_path = _path.Substring(_path.LastIndexOf("/") + 1);
}
if (string.IsNullOrEmpty(_parentid))
{
page.ParentId = null;
@ -265,8 +335,8 @@
else
{
page.ParentId = Int32.Parse(_parentid);
Page parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
if (parent.Path == "")
var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
if (parent.Path == string.Empty)
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
}
@ -275,6 +345,7 @@
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
}
}
Page child;
switch (_insert)
{
@ -293,21 +364,27 @@
page.Order = int.MaxValue;
break;
}
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
page.EditMode = (_mode == "edit" ? true : false);
page.ThemeType = _themetype;
page.LayoutType = (_layouttype == null ? "" : _layouttype);
page.Icon = (_icon == null ? "" : _icon);
page.Permissions = _permissionGrid.GetPermissions();
if (page.ThemeType == PageState.Site.DefaultThemeType)
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)
{
page.ThemeType = "";
page.ThemeType = string.Empty;
}
if (page.LayoutType == PageState.Site.DefaultLayoutType)
page.LayoutType = (_layouttype != "-") ? _layouttype : string.Empty;
if (!string.IsNullOrEmpty(page.LayoutType) && page.LayoutType == PageState.Site.DefaultLayoutType)
{
page.LayoutType = "";
page.LayoutType = string.Empty;
}
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
{
page.DefaultContainerType = string.Empty;
}
page.Icon = (_icon == null ? string.Empty : _icon);
page.Permissions = _permissionGrid.GetPermissions();
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
page.UserId = null;

View File

@ -4,31 +4,25 @@
@inject IPageService PageService
@inject IThemeService ThemeService
@if (_themeList != null)
{
<TabStrip>
<TabPanel Name="Settings">
@if (_themeList != null)
{
<table class="table table-borderless">
<tr>
<td>
<label for="Name" class="control-label">Name: </label>
<Label For="Name" HelpText="Enter the page name">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@_name" />
<input id="Name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Path: </label>
<Label For="Parent" HelpText="Select the parent for the page in the site hierarchy">Parent: </Label>
</td>
<td>
<input class="form-control" @bind="@_path" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Parent: </label>
</td>
<td>
<select class="form-control" @onchange="(e => ParentChanged(e))">
<select id="Parent" class="form-control" @onchange="(e => ParentChanged(e))">
<option value="-1">&lt;Site Root&gt;</option>
@foreach (Page page in _pageList)
{
@ -46,10 +40,10 @@
</tr>
<tr>
<td>
<label for="Name" class="control-label">Move: </label>
<Label For="Move" HelpText="Select the location where you would like the page to be moved in relation to other pages">Move: </Label>
</td>
<td>
<select class="form-control" @bind="@_insert">
<select id="Move" class="form-control" @bind="@_insert">
@if (_parentid == _currentparentid)
{
<option value="=">&lt;Maintain Current Location&gt;</option>
@ -76,10 +70,10 @@
</tr>
<tr>
<td>
<label for="Name" class="control-label">Navigation? </label>
<Label For="Navigation" HelpText="Select whether the page is part of the site navigation or hidden">Navigation? </Label>
</td>
<td>
<select class="form-control" @bind="@_isnavigation">
<select id="Navigation" class="form-control" @bind="@_isnavigation">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -87,21 +81,104 @@
</tr>
<tr>
<td>
<label for="Name" class="control-label">Personalizable? </label>
<Label For="Path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used.">Url Path: </Label>
</td>
<td>
<select class="form-control" @bind="@_ispersonalizable">
<option value="True">Yes</option>
<option value="False">No</option>
<input id="Path" class="form-control" @bind="@_path" />
</td>
</tr>
<tr>
<td>
<Label For="Url" HelpText="Optionally enter a url which this page should redirect to when a user navigates to it">Redirect: </Label>
</td>
<td>
<input id="Url" class="form-control" @bind="@_url" />
</td>
</tr>
</table>
<Section Name="Appearance">
<table class="table table-borderless">
<tr>
<td>
<Label For="Title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used.">Title: </Label>
</td>
<td>
<input id="Title" class="form-control" @bind="@_title" />
</td>
</tr>
<tr>
<td>
<Label For="Theme" HelpText="Select the theme for this page">Theme: </Label>
</td>
<td>
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;Inherit From Site&gt;</option>
@foreach (var theme in _themes)
{
if (theme.TypeName == _themetype)
{
<option value="@theme.TypeName" selected>@theme.Name</option>
}
else
{
<option value="@theme.TypeName">@theme.Name</option>
}
}
</select>
</td>
</tr>
@if (_layouts.Count > 0)
{
<tr>
<td>
<Label For="Layout" HelpText="Select a layout for the page (if the selected theme supports it)">Layout: </Label>
</td>
<td>
<select id="Layout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;Inherit From Site&gt;</option>
@foreach (var layout in _layouts)
{
if (layout.TypeName == _layouttype)
{
<option value="@(layout.TypeName)" selected>@(layout.Name)</option>
}
else
{
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the page">Default Container: </Label>
</td>
<td>
<select id="defaultContainer" class="form-control" @bind="@_containertype">
<option value="-">&lt;Inherit From Site&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Default Mode? </label>
<Label For="Icon" HelpText="Optionally provide an icon for this page which will be displayed in the site navigation">Icon: </Label>
</td>
<td>
<select class="form-control" @bind="@_mode">
<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>
@ -109,132 +186,128 @@
</tr>
<tr>
<td>
<label for="Name" class="control-label">Theme: </label>
<Label For="Personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content">Personalizable? </Label>
</td>
<td>
<select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in _themes)
{
if (item.Key == _themetype)
{
<option value="@item.Key" selected>@item.Value</option>
}
else
{
<option value="@item.Key">@item.Value</option>
}
}
<select id="Personalizable" class="form-control" @bind="@_ispersonalizable">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Layout: </label>
</td>
<td>
<select class="form-control" @bind="@_layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Icon: </label>
</td>
<td>
<input class="form-control" @bind="@_icon" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Permissions: </label>
</td>
<td>
<PermissionGrid EntityName="Page" Permissions="@_permissions" @ref="_permissionGrid" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SavePage">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
</Section>
<br /><br />
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
}
}
</TabPanel>
<TabPanel Name="Permissions">
@if (_permissions != null)
{
<table class="table table-borderless">
<tr>
<td>
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
</td>
</tr>
</table>
}
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SavePage">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
Dictionary<string, string> _themes = new Dictionary<string, string>();
Dictionary<string, string> _panelayouts = new Dictionary<string, string>();
List<Theme> _themeList;
List<Page> _pageList;
int _pageId;
string _name;
string _path;
string _currentparentid;
string _parentid;
string _insert = "=";
List<Page> _children;
int _childid = -1;
string _isnavigation;
string _ispersonalizable;
string _mode;
string _themetype;
string _layouttype;
string _icon;
string _permissions;
string _createdby;
DateTime _createdon;
string _modifiedby;
DateTime _modifiedon;
string _deletedby;
DateTime? _deletedon;
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<Page> _pageList;
private int _pageId;
private string _name;
private string _title;
private string _path;
private string _currentparentid;
private string _parentid;
private string _insert = "=";
private List<Page> _children;
private int _childid = -1;
private string _isnavigation;
private string _url;
private string _ispersonalizable;
private string _mode;
private string _themetype = "-";
private string _layouttype = "-";
private string _containertype = "-";
private string _icon;
private string _permissions = null;
private string _createdby;
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
private string _deletedby;
private DateTime? _deletedon;
#pragma warning disable 649
PermissionGrid _permissionGrid;
private PermissionGrid _permissionGrid;
#pragma warning restore 649
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
try
{
_themeList = await ThemeService.GetThemesAsync();
_pageList = PageState.Pages;
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
_themes = ThemeService.GetThemeTypes(_themeList);
_themeList = await ThemeService.GetThemesAsync();
_themes = ThemeService.GetThemeControls(_themeList);
_pageId = Int32.Parse(PageState.QueryString["id"]);
Page page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
var page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
if (page != null)
{
_name = page.Name;
_title = page.Title;
_path = page.Path;
if (_path.Contains("/"))
{
_path = _path.Substring(_path.LastIndexOf("/") + 1);
}
if (page.ParentId == null)
{
_parentid = "";
_parentid = string.Empty;
}
else
{
_parentid = page.ParentId.ToString();
}
_currentparentid = _parentid;
_isnavigation = page.IsNavigation.ToString();
_url = page.Url;
_ispersonalizable = page.IsPersonalizable.ToString();
_mode = (page.EditMode) ? "edit" : "view";
_themetype = page.ThemeType;
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
if (_themetype == PageState.Site.DefaultThemeType)
{
_themetype = "-";
}
_layouts = ThemeService.GetLayoutControls(_themeList, page.ThemeType);
_layouttype = page.LayoutType;
if (_layouttype == PageState.Site.DefaultLayoutType)
{
_layouttype = "-";
}
_containers = ThemeService.GetContainerControls(_themeList, page.ThemeType);
_containertype = page.DefaultContainerType;
if (string.IsNullOrEmpty(_containertype))
{
_containertype = "-";
}
_icon = page.Icon;
_permissions = page.Permissions;
_createdby = page.CreatedBy;
@ -257,13 +330,26 @@
try
{
_parentid = (string)e.Value;
_children = new List<Page>();
if (_parentid == "-1")
{
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
foreach(Page p in PageState.Pages.Where(item => item.ParentId == null))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
_children.Add(p);
}
}
}
else
{
_children = PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)).ToList();
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
_children.Add(p);
}
}
}
if (_parentid == _currentparentid)
{
@ -287,14 +373,18 @@
try
{
_themetype = (string)e.Value;
if (_themetype != "")
if (_themetype != "-")
{
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_panelayouts = new Dictionary<string, string>();
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containertype = "-";
StateHasChanged();
}
catch (Exception ex)
@ -309,13 +399,15 @@
Page page = null;
try
{
if (_name != "" && !string.IsNullOrEmpty(_themetype) && (_panelayouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)))
if (_name != string.Empty)
{
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
string currentPath = page.Path;
page.Name = _name;
page.Title = _title;
if (_path == "" && _name.ToLower() != "home")
if (_path == string.Empty && _name.ToLower() != "home")
{
_path = _name;
}
@ -323,7 +415,7 @@
{
_path = _path.Substring(_path.LastIndexOf("/") + 1);
}
if (string.IsNullOrEmpty(_parentid))
if (string.IsNullOrEmpty(_parentid) || _parentid == "-1")
{
page.ParentId = null;
page.Path = Utilities.GetFriendlyUrl(_path);
@ -332,7 +424,7 @@
{
page.ParentId = Int32.Parse(_parentid);
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId);
if (parent.Path == "")
if (parent.Path == string.Empty)
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
}
@ -363,26 +455,31 @@
}
}
page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation));
page.Url = _url;
page.EditMode = (_mode == "edit");
page.ThemeType = _themetype;
page.LayoutType = _layouttype ?? "";
page.Icon = _icon ?? "";
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
{
page.ThemeType = string.Empty;
}
page.LayoutType = (_layouttype != "-") ? _layouttype : string.Empty;
if (!string.IsNullOrEmpty(page.LayoutType) && page.LayoutType == PageState.Site.DefaultLayoutType)
{
page.LayoutType = string.Empty;
}
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
{
page.DefaultContainerType = string.Empty;
}
page.Icon = _icon ?? string.Empty;
page.Permissions = _permissionGrid.GetPermissions();
if (page.ThemeType == PageState.Site.DefaultThemeType)
{
page.ThemeType = "";
}
if (page.LayoutType == PageState.Site.DefaultLayoutType)
{
page.LayoutType = "";
}
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
page.UserId = null;
page = await PageService.UpdatePageAsync(page);
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
if (_currentparentid == "")
if (_currentparentid == string.Empty)
{
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, null);
}
@ -406,7 +503,7 @@
}
else
{
AddModuleMessage("You Must Provide Page Name And Theme", MessageType.Warning);
AddModuleMessage("You Must Provide Page Name", MessageType.Warning);
}
}
catch (Exception ex)

View File

@ -9,8 +9,8 @@
<Pager Items="@PageState.Pages.Where(item => !item.IsDeleted)">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
</Header>
<Row>
@ -22,13 +22,14 @@
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
private async Task DeletePage(Page page)
{
try
{
page.IsDeleted = true;
await PageService.UpdatePageAsync(page);
await logger.LogInformation("Page Deleted {Page}", page);
NavigationManager.NavigateTo(NavigateUrl("admin/pages"));

View File

@ -6,66 +6,66 @@
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
<Label For="name" HelpText="The name of this field">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@_name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Title: </label>
<Label For="title" HelpText="The title of the field">Title: </Label>
</td>
<td>
<input class="form-control" @bind="@_title" />
<input id="title" class="form-control" @bind="@_title" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Description: </label>
<Label For="description" HelpText="What the profile field is">Description: </Label>
</td>
<td>
<textarea class="form-control" @bind="@_description" rows="5"></textarea>
<textarea id="description" class="form-control" @bind="@_description" rows="5"></textarea>
</td>
</tr>
<tr>
<td>
<label class="control-label">Category: </label>
<Label For="category" HelpText="What larger category does this field belong to">Category: </Label>
</td>
<td>
<input class="form-control" @bind="@_category" />
<input id="category" class="form-control" @bind="@_category" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Order: </label>
<Label For="order" HelpText="What place is this field in a larger category list">Order: </Label>
</td>
<td>
<input class="form-control" @bind="@_vieworder" />
<input id="order" class="form-control" @bind="@_vieworder" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Length: </label>
<Label For="length" HelpText="What is the max amount of characters should this field accept">Length: </Label>
</td>
<td>
<input class="form-control" @bind="@_maxlength" />
<input id="length" class="form-control" @bind="@_maxlength" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Default Value: </label>
<Label For="defaultVal" HelpText="What value do you want this field to start with">Default Value: </Label>
</td>
<td>
<input class="form-control" @bind="@_defaultvalue" />
<input id="defaultVal" class="form-control" @bind="@_defaultvalue" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Required? </label>
<Label For="required" HelpText="Is a user required to input something into this field?">Required? </Label>
</td>
<td>
<select class="form-control" @bind="@_isrequired">
<select id="required" class="form-control" @bind="@_isrequired">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -73,10 +73,10 @@
</tr>
<tr>
<td>
<label class="control-label">Private? </label>
<Label For="private" HelpText="Is this field private?">Private? </Label>
</td>
<td>
<select class="form-control" @bind="@_isprivate">
<select id="private" class="form-control" @bind="@_isprivate">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -87,19 +87,20 @@
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
public override string Actions { get { return "Add,Edit"; } }
private int _profileid = -1;
private string _name = string.Empty;
private string _title = string.Empty;
private string _description = string.Empty;
private string _category = string.Empty;
private string _vieworder = "0";
private string _maxlength = "0";
private string _defaultvalue = string.Empty;
private string _isrequired = "False";
private string _isprivate = "False";
int _profileid = -1;
string _name = "";
string _title = "";
string _description = "";
string _category = "";
string _vieworder = "0";
string _maxlength = "0";
string _defaultvalue = "";
string _isrequired = "False";
string _isprivate = "False";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
public override string Actions => "Add,Edit";
protected override async Task OnInitializedAsync()
{
@ -108,7 +109,7 @@
if (PageState.QueryString.ContainsKey("id"))
{
_profileid = Int32.Parse(PageState.QueryString["id"]);
Profile profile = await ProfileService.GetProfileAsync(_profileid);
var profile = await ProfileService.GetProfileAsync(_profileid);
if (profile != null)
{
_name = profile.Name;
@ -143,6 +144,7 @@
{
profile = new Profile();
}
profile.Name = _name;
profile.Title = _title;
profile.Description = _description;
@ -152,7 +154,14 @@
profile.DefaultValue = _defaultvalue;
profile.IsRequired = (_isrequired == null ? false : Boolean.Parse(_isrequired));
profile.IsPrivate = (_isprivate == null ? false : Boolean.Parse(_isprivate));
if (_profileid != -1)
{
profile = await ProfileService.UpdateProfileAsync(profile);
}else
{
profile = await ProfileService.AddProfileAsync(profile);
}
await logger.LogInformation("Profile Saved {Profile}", profile);
NavigationManager.NavigateTo(NavigateUrl());
}

View File

@ -12,8 +12,8 @@ else
<Pager Items="@_profiles">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
</Header>
<Row>
@ -25,9 +25,9 @@ else
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private List<Profile> _profiles;
List<Profile> _profiles;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{

View File

@ -5,24 +5,8 @@
@inject IModuleService ModuleService
@inject IPageService PageService
<div class="container-fluid">
<div class="form-group">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#Pages" role="tab">
Pages
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#Modules" role="tab">
Modules
</a>
</li>
</ul>
<div class="tab-content">
<div id="Pages" class="tab-pane fade show active" role="tabpanel">
<TabStrip>
<TabPanel Name="Pages">
@if (_pages == null)
{
<br />
@ -32,8 +16,8 @@
{
<Pager Items="@_pages">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
<th>Deleted By</th>
<th>Deleted On</th>
@ -47,8 +31,8 @@
</Row>
</Pager>
}
</div>
<div id="Modules" class="tab-pane fade" role="tabpanel">
</TabPanel>
<TabPanel Name="Modules">
@if (_modules == null)
{
<br />
@ -58,8 +42,8 @@
{
<Pager Items="@_modules">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Page</th>
<th>Module</th>
<th>Deleted By</th>
@ -75,16 +59,14 @@
</Row>
</Pager>
}
</div>
</div>
</div>
</div>
</TabPanel>
</TabStrip>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private List<Page> _pages;
private List<Module> _modules;
List<Page> _pages;
List<Module> _modules;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
@ -147,7 +129,7 @@
{
try
{
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(module.PageModuleId);
var pagemodule = await PageModuleService.GetPageModuleAsync(module.PageModuleId);
pagemodule.IsDeleted = false;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await logger.LogInformation("Module Restored {Module}", module);
@ -168,10 +150,12 @@
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
// check if there are any remaining module instances in the site
_modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
if (!_modules.Exists(item => item.ModuleId == module.ModuleId))
{
await ModuleService.DeleteModuleAsync(module.ModuleId);
}
await logger.LogInformation("Module Permanently Deleted {Module}", module);
await Load();
StateHasChanged();

View File

@ -3,60 +3,74 @@
@inject NavigationManager NavigationManager
@inject IUserService UserService
@if (_message != "")
@if (PageState.Site.AllowRegistration)
{
<ModuleMessage Message="@_message" Type="MessageType.Info" />
}
<AuthorizeView>
<Authorizing>
<text>...</text>
</Authorizing>
<Authorized>
<ModuleMessage Message="You Are Already Registered" Type="MessageType.Info" />
</Authorized>
<NotAuthorized>
<ModuleMessage Message="Please Note That Registration Requires A Valid Email Address In Order To Verify Your Identity" Type="MessageType.Info" />
<div class="container">
<div class="container">
<div class="form-group">
<label for="Username" class="control-label">Username: </label>
<input type="text" class="form-control" placeholder="Username" @bind="@_username" id="Username"/>
<input type="text" class="form-control" placeholder="Username" @bind="@_username" id="Username" />
</div>
<div class="form-group">
<label for="Password" class="control-label">Password: </label>
<input type="password" class="form-control" placeholder="Password" @bind="@_password" id="Password"/>
<input type="password" class="form-control" placeholder="Password" @bind="@_password" id="Password" />
</div>
<div class="form-group">
<label for="Confirm" class="control-label">Confirm Password: </label>
<input type="password" class="form-control" placeholder="Password" @bind="@_confirm"id="Confirm" />
<input type="password" class="form-control" placeholder="Password" @bind="@_confirm" id="Confirm" />
</div>
<div class="form-group">
<label for="Email" class="control-label">Email: </label>
<input type="text" class="form-control" placeholder="Email" @bind="@_email" id="Email"/>
<input type="text" class="form-control" placeholder="Email" @bind="@_email" id="Email" />
</div>
<div class="form-group">
<label for="DisplayName" class="control-label">Full Name: </label>
<input type="text" class="form-control" placeholder="Full Name" @bind="@_displayName" id="DisplayName"/>
<input type="text" class="form-control" placeholder="Full Name" @bind="@_displayName" id="DisplayName" />
</div>
<button type="button" class="btn btn-primary" @onclick="Register">Register</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
</div>
</div>
</NotAuthorized>
</AuthorizeView>
}
else
{
<ModuleMessage Message="Registration is Disabled For This Site" Type="MessageType.Info" />
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } }
private string _username = string.Empty;
private string _password = string.Empty;
private string _confirm = string.Empty;
private string _email = string.Empty;
private string _displayName = string.Empty;
string _message = "Please Note That Registration Requires A Valid Email Address In Order To Verify Your Identity";
string _username = "";
string _password = "";
string _confirm = "";
string _email = "";
string _displayName = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
private async Task Register()
{
try
{
_message = "";
if (_username != "" && _password != "" && _confirm != "" && _email != "")
bool _isEmailValid = Utilities.IsValidEmail(_email);
if (_username != "" && _password != "" && _confirm != "" && _isEmailValid)
{
if (_password == _confirm)
{
User user = new User
var user = new User
{
SiteId = PageState.Site.SiteId,
Username = _username,
DisplayName = (_displayName == "" ? _username : _displayName),
DisplayName = (_displayName == string.Empty ? _username : _displayName),
Email = _email,
Password = _password
};
@ -92,6 +106,6 @@
private void Cancel()
{
NavigationManager.NavigateTo(NavigateUrl(""));
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
}
}

View File

@ -21,11 +21,11 @@
</div>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Anonymous; } }
private string _username = string.Empty;
private string _password = string.Empty;
private string _confirm = string.Empty;
string _username = "";
string _password = "";
string _confirm = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
protected override void OnInitialized()
{
@ -35,7 +35,7 @@
}
else
{
NavigationManager.NavigateTo(NavigateUrl(""));
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
}
}
@ -43,11 +43,11 @@
{
try
{
if (_username != "" && _password != "" && _confirm != "")
if (_username != string.Empty && _password != string.Empty && _confirm != string.Empty)
{
if (_password == _confirm)
{
User user = new User
var user = new User
{
SiteId = PageState.Site.SiteId,
Username = _username,
@ -85,6 +85,6 @@
private void Cancel()
{
NavigationManager.NavigateTo(NavigateUrl(""));
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
}
}

View File

@ -6,37 +6,26 @@
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
<Label For="name" HelpText="Name Of The Role">Name:</Label>
</td>
<td>
<input class="form-control" @bind="@name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Description: </label>
<Label For="description" HelpText="A Short Description Of The Role Which Describes Its Purpose">Description:</Label>
</td>
<td>
<textarea class="form-control" @bind="@description" rows="5"></textarea>
<textarea id="description" class="form-control" @bind="@_description" rows="5"></textarea>
</td>
</tr>
<tr>
<td>
<label class="control-label">Auto Assigned? </label>
<Label For="isautoassigned" HelpText="Indicates Whether Or Not New Users Are Automatically Assigned To This Role">Auto Assigned?</Label>
</td>
<td>
<select class="form-control" @bind="@isautoassigned">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<label class="control-label">System Role? </label>
</td>
<td>
<select class="form-control" @bind="@issystem">
<select id="isautoassigned" class="form-control" @bind="@_isautoassigned">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -47,21 +36,20 @@
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private string _name = string.Empty;
private string _description = string.Empty;
private string _isautoassigned = "False";
string name = "";
string description = "";
string isautoassigned = "False";
string issystem = "False";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
private async Task SaveRole()
{
Role role = new Role();
var role = new Role();
role.SiteId = PageState.Page.SiteId;
role.Name = name;
role.Description = description;
role.IsAutoAssigned = (isautoassigned == null ? false : Boolean.Parse(isautoassigned));
role.IsSystem = (issystem == null ? false : Boolean.Parse(issystem));
role.Name = _name;
role.Description = _description;
role.IsAutoAssigned = (_isautoassigned == null ? false : Boolean.Parse(_isautoassigned));
role.IsSystem = false;
try
{

View File

@ -6,37 +6,26 @@
<table class="table table-borderless">
<tr>
<td>
<Label For="_name" Class="control-label" HelpText="Name Of The Role">Name: </Label>
<Label For="name" HelpText="Name Of The Role">Name:</Label>
</td>
<td>
<input id="_name" class="form-control" @bind="@_name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<Label For="_description" Class="control-label" HelpText="A Short Description Of The Role Which Describes Its Purpose">Description: </Label>
<Label For="description" HelpText="A Short Description Of The Role Which Describes Its Purpose">Description:</Label>
</td>
<td>
<textarea id="_description" class="form-control" @bind="@_description" rows="5"></textarea>
<textarea id="description" class="form-control" @bind="@_description" rows="5"></textarea>
</td>
</tr>
<tr>
<td>
<Label For="_isautoassigned" Class="control-label" HelpText="Indicates Whether Or Not New Users Are Automatically Assigned To This Role">Auto Assigned? </Label>
<Label For="isautoassigned" HelpText="Indicates Whether Or Not New Users Are Automatically Assigned To This Role">Auto Assigned?</Label>
</td>
<td>
<select id="_isautoassigned" class="form-control" @bind="@_isautoassigned">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="_issystem" Class="control-label" HelpText="Indicates Whether Or Not This Is A System Role. System Roles Are Protected And Cannot Be Deleted.">System Role? </Label>
</td>
<td>
<select id="_issystem" class="form-control" @bind="@_issystem">
<select id="isautoassigned" class="form-control" @bind="@_isautoassigned">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -47,26 +36,24 @@
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private int _roleid;
private string _name = string.Empty;
private string _description = string.Empty;
private string _isautoassigned = "False";
int _roleid;
string _name = "";
string _description = "";
string _isautoassigned = "False";
string _issystem = "False";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
try
{
_roleid = Int32.Parse(PageState.QueryString["id"]);
Role role = await RoleService.GetRoleAsync(_roleid);
var role = await RoleService.GetRoleAsync(_roleid);
if (role != null)
{
_name = role.Name;
_description = role.Description;
_isautoassigned = role.IsAutoAssigned.ToString();
_issystem = role.IsSystem.ToString();
}
}
catch (Exception ex)
@ -78,11 +65,11 @@
private async Task SaveRole()
{
Role role = await RoleService.GetRoleAsync(_roleid);
var role = await RoleService.GetRoleAsync(_roleid);
role.Name = _name;
role.Description = _description;
role.IsAutoAssigned = (_isautoassigned != null && Boolean.Parse(_isautoassigned));
role.IsSystem = (_issystem != null && Boolean.Parse(_issystem));
role.IsSystem = false;
try
{

View File

@ -12,22 +12,24 @@ else
<Pager Items="@_roles">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" /></td>
<td><ActionDialog Header="Delete Role" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Role?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteRole(context))" /></td>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Disabled="@(context.IsSystem)" /></td>
<td><ActionDialog Header="Delete Role" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Role?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteRole(context))" Disabled="@(context.IsSystem)" /></td>
<td><ActionLink Action="Users" Parameters="@($"id=" + context.RoleId.ToString())" /></td>
<td>@context.Name</td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private List<Role> _roles;
List<Role> _roles;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnParametersSetAsync()
{

View File

@ -0,0 +1,201 @@
@namespace Oqtane.Modules.Admin.Roles
@inherits ModuleBase
@inject IRoleService RoleService
@inject IUserRoleService UserRoleService
@if (userroles == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table table-borderless">
<tr>
<td>
<Label For="role" HelpText="The role you are assigning users to">Role: </Label>
</td>
<td>
<input id="role" class="form-control" @bind="@name" disabled />
</td>
</tr>
<tr>
<td>
<Label For="user" HelpText="Select a user">User: </Label>
</td>
<td>
<select id="user" class="form-control" @bind="@userid">
<option value="-1">&lt;Select User&gt;</option>
@foreach (UserRole userrole in users)
{
<option value="@(userrole.UserId)">@userrole.User.DisplayName</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="effectiveDate" HelpText="The date that this role assignment is active">Effective Date: </Label>
</td>
<td>
<input id="effectiveDate" class="form-control" @bind="@effectivedate" />
</td>
</tr>
<tr>
<td>
<Label For="expiryDate" HelpText="The date that this role assignment expires">Expiry Date: </Label>
</td>
<td>
<input id="expiryDate" class="form-control" @bind="@expirydate" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveUserRole">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<hr class="app-rule" />
<p align="center">
<Pager Items="@userroles">
<Header>
<th>Users</th>
<th>&nbsp;</th>
</Header>
<Row>
<td>@context.User.DisplayName</td>
<td>
<button type="button" class="btn btn-danger" @onclick=@(async () => await DeleteUserRole(context.UserRoleId))>Delete</button>
</td>
</Row>
</Pager>
</p>
}
@code {
private int roleid;
private string name = string.Empty;
private List<UserRole> users;
private int userid = -1;
private string effectivedate = string.Empty;
private string expirydate = string.Empty;
private List<UserRole> userroles;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
try
{
roleid = Int32.Parse(PageState.QueryString["id"]);
Role role = await RoleService.GetRoleAsync(roleid);
name = role.Name;
users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
users = users.Where(item => item.Role.Name == Constants.RegisteredRole).ToList();
await GetUserRoles();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Users {Error}", ex.Message);
AddModuleMessage("Error Loading Users", MessageType.Error);
}
}
private async Task GetUserRoles()
{
try
{
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
userroles = userroles.Where(item => item.RoleId == roleid).ToList();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading User Roles {RoleId} {Error}", roleid, ex.Message);
AddModuleMessage("Error Loading User Roles", MessageType.Error);
}
}
private async Task SaveUserRole()
{
try
{
if (userid != -1)
{
var userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault();
if (userrole != null)
{
if (string.IsNullOrEmpty(effectivedate))
{
userrole.EffectiveDate = null;
}
else
{
userrole.EffectiveDate = DateTime.Parse(effectivedate);
}
if (string.IsNullOrEmpty(expirydate))
{
userrole.ExpiryDate = null;
}
else
{
userrole.ExpiryDate = DateTime.Parse(expirydate);
}
await UserRoleService.UpdateUserRoleAsync(userrole);
}
else
{
userrole = new UserRole();
userrole.UserId = userid;
userrole.RoleId = roleid;
if (string.IsNullOrEmpty(effectivedate))
{
userrole.EffectiveDate = null;
}
else
{
userrole.EffectiveDate = DateTime.Parse(effectivedate);
}
if (string.IsNullOrEmpty(expirydate))
{
userrole.ExpiryDate = null;
}
else
{
userrole.ExpiryDate = DateTime.Parse(expirydate);
}
await UserRoleService.AddUserRoleAsync(userrole);
}
await GetUserRoles();
await logger.LogInformation("User Assigned To Role {UserRole}", userrole);
AddModuleMessage("User Assigned To Role", MessageType.Success);
}
else
{
AddModuleMessage("You Must Select A User", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving User Roles {RoleId} {Error}", roleid, ex.Message);
AddModuleMessage("Error Saving User Roles", MessageType.Error);
}
}
private async Task DeleteUserRole(int UserRoleId)
{
try
{
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
await GetUserRoles();
await logger.LogInformation("User Removed From Role {UserRoleId}", UserRoleId);
AddModuleMessage("User Removed From Role", MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Removing User From Role {UserRoleId} {Error}", UserRoleId, ex.Message);
AddModuleMessage("Error Removing User From Role", MessageType.Error);
}
}
}

View File

@ -12,91 +12,113 @@
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
<Label For="name" HelpText="Enter the site name">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@_name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Tenant: </label>
<Label For="tenant" HelpText="Enter the tenant for the site">Tenant: </Label>
</td>
<td>
<input class="form-control" @bind="@_tenant" readonly />
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
</td>
</tr>
<tr>
<td>
<label class="control-label">Aliases: </label>
<Label For="alias" HelpText="Enter the alias for the server">Aliases: </Label>
</td>
<td>
<textarea class="form-control" @bind="@_urls" rows="3"></textarea>
<textarea id="alias" class="form-control" @bind="@_urls" rows="3"></textarea>
</td>
</tr>
<tr>
<td>
<label class="control-label">Logo: </label>
<Label For="logo" HelpText="Upload a logo for the site">Logo: </Label>
</td>
<td>
<FileManager FileId="@_logofileid.ToString()" @ref="_filemanager" />
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Default Theme: </label>
<Label For="favicon" HelpText="Select Your default icon">Favicon: </Label>
</td>
<td>
<select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in _themes)
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
</td>
</tr>
<tr>
<td>
<Label For="defaultTheme" HelpText="Select the sites default theme">Default Theme: </Label>
</td>
<td>
<select id="defaultTheme" class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;Select Theme&gt;</option>
@foreach (var theme in _themes)
{
if (item.Key == _themetype)
if (theme.TypeName == _themetype)
{
<option value="@item.Key" selected>@item.Value</option>
<option value="@theme.TypeName" selected>@theme.Name</option>
}
else
{
<option value="@item.Key">@item.Value</option>
<option value="@theme.TypeName">@theme.Name</option>
}
}
</select>
</td>
</tr>
<tr>
<td>
<label class="control-label">Default Layout: </label>
</td>
<td>
<select class="form-control" @bind="@_layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
@if (_layouts.Count > 0)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label class="control-label">Default Container: </label>
<Label For="defaultLayout" HelpText="Select the sites default layout">Default Layout: </Label>
</td>
<td>
<select class="form-control" @bind="@_containertype">
<option value="">&lt;Select Container&gt;</option>
@foreach (KeyValuePair<string, string> container in _containers)
<select id="defaultLayout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;Select Layout&gt;</option>
@foreach (var layout in _layouts)
{
<option value="@container.Key">@container.Value</option>
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the site">Default Container: </Label>
</td>
<td>
<select id="defaultContainer" class="form-control" @bind="@_containertype">
<option value="-">&lt;Select Container&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label class="control-label">Is Deleted? </label>
<Label For="allowRegister" HelpText="Do you want the users to be able to register for an account on the site">Allow User Registration? </Label>
</td>
<td>
<select class="form-control" @bind="@_isdeleted">
<select id="allowRegister" class="form-control" @bind="@_allowregistration">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="isDeleted" HelpText="Is this site deleted?">Is Deleted? </Label>
</td>
<td>
<select id="isDeleted" class="form-control" @bind="@_isdeleted">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -104,53 +126,82 @@
</tr>
</table>
<a data-toggle="collapse" class="app-link-unstyled" href="#SMTP" aria-expanded="false" aria-controls="SMTP">
<h5><i class="oi oi-chevron-bottom"></i>&nbsp;SMTP Settings</h5><hr class="app-rule" />
</a>
<div class="collapse" id="SMTP">
<Section Name="SMTP" Heading="SMTP Settings">
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Host: </label>
<Label For="host" HelpText="Enter the host name of the server">Host: </Label>
</td>
<td>
<input class="form-control" @bind="@_smtphost" />
<input id="host" class="form-control" @bind="@_smtphost" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Port: </label>
<Label For="port" HelpText="Enter the port number for the server">Port: </Label>
</td>
<td>
<input class="form-control" @bind="@_smtpport" />
<input id="port" class="form-control" @bind="@_smtpport" />
</td>
</tr>
<tr>
<td>
<label class="control-label">SSL Enabled: </label>
<Label For="enabledSSl" HelpText="Specifiy if SSL is enabled for your server">SSL Enabled: </Label>
</td>
<td>
<input class="form-control" @bind="@_smtpssl" />
<input id="enabledSSl" class="form-control" @bind="@_smtpssl" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Username: </label>
<Label For="username" HelpText="Enter the username for the server">Username: </Label>
</td>
<td>
<input class="form-control" @bind="@_smtpusername" />
<input id="username" class="form-control" @bind="@_smtpusername" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Password: </label>
<Label For="password" HelpText="Enter the password for the server">Password: </Label>
</td>
<td>
<input type="password" class="form-control" @bind="@_smtppassword" />
<input id="password" type="password" class="form-control" @bind="@_smtppassword" />
</td>
</tr>
</table>
</div>
</Section>
<Section Name="PWA" Heading="Progressive Web Application Settings">
<table class="table table-borderless">
<tr>
<td>
<Label For="isEnabled" HelpText="Select whether you would like this site to be available as a Progressive Web Application (PWA)">Is Enabled? </Label>
</td>
<td>
<select id="isEnabled" class="form-control" @bind="@_pwaisenabled">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="appIcon" HelpText="Include an application icon for your PWA. It should be a PNG which is 192 X 192 pixels in dimension.">App Icon: </Label>
</td>
<td>
<FileManager FileId="@_pwaappiconfileid" Filter="png" @ref="_pwaappiconfilemanager" />
</td>
</tr>
<tr>
<td>
<Label For="splashIcon" HelpText="Include a splash icon for your PWA. It should be a PNG which is 512 X 512 pixels in dimension.">Splash Icon: </Label>
</td>
<td>
<FileManager FileId="@_pwasplashiconfileid" Filter="png" @ref="_pwasplashiconfilemanager" />
</td>
</tr>
</table>
</Section>
<br />
<button type="button" class="btn btn-success" @onclick="SaveSite">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@ -160,37 +211,42 @@
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private string _name = string.Empty;
private List<Tenant> _tenantList;
private string _tenant = string.Empty;
private List<Alias> _aliasList;
private string _urls = string.Empty;
private int _logofileid = -1;
private FileManager _logofilemanager;
private int _faviconfileid = -1;
private FileManager _faviconfilemanager;
private string _themetype = "-";
private string _layouttype = "-";
private string _containertype = "-";
private string _allowregistration;
private string _smtphost = string.Empty;
private string _smtpport = string.Empty;
private string _smtpssl = string.Empty;
private string _smtpusername = string.Empty;
private string _smtppassword = string.Empty;
private string _pwaisenabled;
private int _pwaappiconfileid = -1;
private FileManager _pwaappiconfilemanager;
private int _pwasplashiconfileid = -1;
private FileManager _pwasplashiconfilemanager;
private string _createdby;
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
private string _deletedby;
private DateTime? _deletedon;
private string _isdeleted;
Dictionary<string, string> _themes;
Dictionary<string, string> _panelayouts;
Dictionary<string, string> _containers;
List<Theme> _themeList;
string _name = "";
List<Tenant> _tenantList;
string _tenant = "";
List<Alias> _aliasList;
string _urls = "";
int _logofileid = -1;
FileManager _filemanager;
string _themetype;
string _layouttype;
string _containertype;
string _smtphost = "";
string _smtpport = "";
string _smtpssl = "";
string _smtpusername = "";
string _smtppassword = "";
string _createdby;
DateTime _createdon;
string _modifiedby;
DateTime _modifiedon;
string _deletedby;
DateTime? _deletedon;
string _isdeleted;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
@ -198,7 +254,7 @@
{
_themeList = await ThemeService.GetThemesAsync();
_aliasList = await AliasService.GetAliasesAsync();
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId, PageState.Alias);
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
if (site != null)
{
_name = site.Name;
@ -212,17 +268,48 @@
{
_logofileid = site.LogoFileId.Value;
}
_themetype = site.DefaultThemeType;
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_layouttype = site.DefaultLayoutType;
_containertype = site.DefaultContainerType;
Dictionary<string, string> settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
_smtphost = SettingService.GetSetting(settings, "SMTPHost", "");
_smtpport = SettingService.GetSetting(settings, "SMTPPort", "");
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "");
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", "");
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", "");
if (site.FaviconFileId != null)
{
_faviconfileid = site.FaviconFileId.Value;
}
_themes = ThemeService.GetThemeControls(_themeList);
_themetype = site.DefaultThemeType;
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_layouttype = site.DefaultLayoutType;
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = site.DefaultContainerType;
_allowregistration = site.AllowRegistration.ToString();
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", string.Empty);
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
_pwaisenabled = site.PwaIsEnabled.ToString();
if (site.PwaAppIconFileId != null)
{
_pwaappiconfileid = site.PwaAppIconFileId.Value;
}
if (site.PwaSplashIconFileId != null)
{
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
}
_pwaisenabled = site.PwaIsEnabled.ToString();
if (site.PwaAppIconFileId != null)
{
_pwaappiconfileid = site.PwaAppIconFileId.Value;
}
if (site.PwaSplashIconFileId != null)
{
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
}
_createdby = site.CreatedBy;
_createdon = site.CreatedOn;
@ -232,9 +319,6 @@
_deletedon = site.DeletedOn;
_isdeleted = site.IsDeleted.ToString();
}
_themes = ThemeService.GetThemeTypes(_themeList);
_containers = ThemeService.GetContainerTypes(_themeList);
}
catch (Exception ex)
{
@ -248,14 +332,18 @@
try
{
_themetype = (string)e.Value;
if (_themetype != "")
if (_themetype != "-")
{
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_panelayouts = new Dictionary<string, string>();
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containertype = "-";
StateHasChanged();
}
catch (Exception ex)
@ -269,9 +357,9 @@
{
try
{
if (_name != "" && _urls != "" && !string.IsNullOrEmpty(_themetype) && (_panelayouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)) && !string.IsNullOrEmpty(_containertype))
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && (_layouts.Count == 0 || _layouttype != "-") && _containertype != "-")
{
bool unique = true;
var unique = true;
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
if (_aliasList.Exists(item => item.Name == name && item.SiteId != PageState.Alias.SiteId && item.TenantId != PageState.Alias.TenantId))
@ -279,27 +367,44 @@
unique = false;
}
}
if (unique)
{
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId, PageState.Alias);
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
if (site != null)
{
site.Name = _name;
site.LogoFileId = null;
int logofileid = _filemanager.GetFileId();
var logofileid = _logofilemanager.GetFileId();
if (logofileid != -1)
{
site.LogoFileId = logofileid;
}
site.DefaultThemeType = _themetype;
site.DefaultLayoutType = (_layouttype == null ? "" : _layouttype);
site.DefaultLayoutType = (_layouttype == "-" ? string.Empty : _layouttype);
site.DefaultContainerType = _containertype;
site.AllowRegistration = (_allowregistration == null ? true : Boolean.Parse(_allowregistration));
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
site = await SiteService.UpdateSiteAsync(site, PageState.Alias);
site.PwaIsEnabled = (_pwaisenabled == null ? true : Boolean.Parse(_pwaisenabled));
var pwaappiconfileid = _pwaappiconfilemanager.GetFileId();
if (pwaappiconfileid != -1)
{
site.PwaAppIconFileId = pwaappiconfileid;
}
var pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId();
if (pwasplashiconfileid != -1)
{
site.PwaSplashIconFileId = pwasplashiconfileid;
}
site = await SiteService.UpdateSiteAsync(site);
_urls = _urls.Replace("\n", ",");
string[] names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
{
if (!names.Contains(alias.Name))
@ -307,6 +412,7 @@
await AliasService.DeleteAliasAsync(alias.AliasId);
}
}
foreach (string name in names)
{
if (!_aliasList.Exists(item => item.Name == name))
@ -319,7 +425,7 @@
}
}
Dictionary<string, string> settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
SettingService.SetSetting(settings, "SMTPHost", _smtphost);
SettingService.SetSetting(settings, "SMTPPort", _smtpport);
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl);

View File

@ -5,7 +5,9 @@
@inject IAliasService AliasService
@inject ISiteService SiteService
@inject IThemeService ThemeService
@inject ISiteTemplateService SiteTemplateService
@inject IUserService UserService
@inject IInstallationService InstallationService
@if (_tenants == null)
{
@ -16,11 +18,87 @@ else
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Tenant: </label>
<Label For="name" HelpText="Enter the name of the site">Site Name: </Label>
</td>
<td>
<select class="form-control" @onchange="(e => TenantChanged(e))">
<option value="-1">&lt;Select Tenant&gt;</option>
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<Label For="alias" HelpText="Enter the alias for the server">Aliases: </Label>
</td>
<td>
<textarea id="alias" class="form-control" @bind="@_urls" rows="3"></textarea>
</td>
</tr>
<tr>
<td>
<Label For="defaultTheme" HelpText="Select the default theme for the website">Default Theme: </Label>
</td>
<td>
<select id="defaultTheme" class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;Select Theme&gt;</option>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
}
</select>
</td>
</tr>
@if (_layouts.Count > 0)
{
<tr>
<td>
<Label For="defaultLayout" HelpText="Select the default layout for the site">Default Layout: </Label>
</td>
<td>
<select id="defaultLayout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;Select Layout&gt;</option>
@foreach (var layout in _layouts)
{
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the site">Default Container: </Label>
</td>
<td>
<select id="defaultContainer" class="form-control" @bind="@_containertype">
<option value="-">&lt;Select Container&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="siteTemplate" HelpText="Select the site template">Site Template: </Label>
</td>
<td>
<select id="siteTemplate" class="form-control" @bind="@_sitetemplatetype">
<option value="-">&lt;Select Site Template&gt;</option>
@foreach (SiteTemplate siteTemplate in _siteTemplates)
{
<option value="@siteTemplate.TypeName">@siteTemplate.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="tenant" HelpText="Select the tenant for the site">Tenant: </Label>
</td>
<td>
<select id="tenant" class="form-control" @onchange="(e => TenantChanged(e))">
<option value="-">&lt;Select Tenant&gt;</option>
<option value="+">&lt;Create New Tenant&gt;</option>
@foreach (Tenant tenant in _tenants)
{
<option value="@tenant.TenantId">@tenant.Name</option>
@ -28,80 +106,92 @@ else
</select>
</td>
</tr>
<tr>
<td>
<label class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Aliases: </label>
</td>
<td>
<textarea class="form-control" @bind="@_urls" rows="3"></textarea>
</td>
</tr>
<tr>
<td>
<label class="control-label">Default Theme: </label>
</td>
<td>
<select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in _themes)
@if (_tenantid == "+")
{
<option value="@item.Key">@item.Value</option>
}
<tr>
<td colspan="2">
<hr class="app-rule" />
</td>
</tr>
<tr>
<td>
<Label For="name" HelpText="Enter the name for the tenant">Tenant Name: </Label>
</td>
<td>
<input id="name" class="form-control" @bind="@_tenantname" />
</td>
</tr>
<tr>
<td>
<Label For="databaseType" HelpText="Select the database type for the tenant">Database Type: </Label>
</td>
<td>
<select id="databaseType" class="custom-select" @bind="@_databasetype">
<option value="LocalDB">Local Database</option>
<option value="SQLServer">SQL Server</option>
</select>
</td>
</tr>
<tr>
<td>
<label class="control-label">Default Layout: </label>
<Label For="server" HelpText="Enter the server for the tenant">Server: </Label>
</td>
<td>
<select class="form-control" @bind="@_layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
<input id="server" type="text" class="form-control" @bind="@_server" />
</td>
</tr>
<tr>
<td>
<Label For="database" HelpText="Enter the database for the tenant">Database: </Label>
</td>
<td>
<input id="database" type="text" class="form-control" @bind="@_database" />
</td>
</tr>
<tr>
<td>
<Label For="integratedSecurity" HelpText="Select if you want integrated security or not">Integrated Security: </Label>
</td>
<td>
<select id="integratedSecurity" class="custom-select" @onchange="SetIntegratedSecurity">
<option value="true" selected>True</option>
<option value="false">False</option>
</select>
</td>
</tr>
@if (!_integratedsecurity)
{
<tr>
<td>
<label class="control-label">Default Container: </label>
<Label For="username" HelpText="Enter the username for the integrated security">Database Username: </Label>
</td>
<td>
<select class="form-control" @bind="@_containertype">
<option value="">&lt;Select Container&gt;</option>
@foreach (KeyValuePair<string, string>container in _containers)
{
<option value="@container.Key">@container.Value</option>
<input id="username" type="text" class="form-control" @bind="@_username" />
</td>
</tr>
<tr>
<td>
<Label For="password" HelpText="Enter the password for the integrated security">Database Password: </Label>
</td>
<td>
<input id="password" type="password" class="form-control" @bind="@_password" />
</td>
</tr>
}
</select>
</td>
</tr>
@if (!_isinitialized)
{
<tr>
<td>
<label class="control-label">Host Username:</label>
<Label For="hostUsername" HelpText="Enter the username of the host for this site">Host Username:</Label>
</td>
<td>
<input class="form-control" @bind="@_username" readonly />
<input id="hostUsername" class="form-control" @bind="@_hostusername" readonly />
</td>
</tr>
<tr>
<td>
<label class="control-label">Host Password:</label>
<Label For="hostPassword" HelpText="Enter the password for the host of this site">Host Password:</Label>
</td>
<td>
<input type="password" class="form-control" @bind="@_password" />
<input id="hostPassword" type="password" class="form-control" @bind="@_hostpassword" />
</td>
</tr>
}
@ -111,54 +201,63 @@ else
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<SiteTemplate> _siteTemplates;
private List<Tenant> _tenants;
private string _tenantid = "-";
Dictionary<string, string> _themes = new Dictionary<string, string>();
Dictionary<string, string> _panelayouts = new Dictionary<string, string>();
Dictionary<string, string> _containers = new Dictionary<string, string>();
private string _tenantname = string.Empty;
private string _databasetype = "LocalDB";
private string _server = "(LocalDb)\\MSSQLLocalDB";
private string _database = "Oqtane-" + DateTime.UtcNow.ToString("yyyyMMddHHmm");
private string _username = string.Empty;
private string _password = string.Empty;
private bool _integratedsecurity = true;
private string _hostusername = Constants.HostUser;
private string _hostpassword = string.Empty;
List<Theme> _themeList;
List<Tenant> _tenants;
string _tenantid = "-1";
string _name = "";
string _urls = "";
string _themetype = "";
string _layouttype = "";
string _containertype = "";
bool _isinitialized = true;
string _username = "";
string _password = "";
private string _name = string.Empty;
private string _urls = string.Empty;
private string _themetype = "-";
private string _layouttype = "-";
private string _containertype = "-";
private string _sitetemplatetype = "-";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
_themeList = await ThemeService.GetThemesAsync();
_tenants = await TenantService.GetTenantsAsync();
_urls = PageState.Alias.Name;
_themes = ThemeService.GetThemeTypes(_themeList);
_containers = ThemeService.GetContainerTypes(_themeList);
_username = Constants.HostUser;
_themeList = await ThemeService.GetThemesAsync();
_themes = ThemeService.GetThemeControls(_themeList);
_siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync();
}
private async void TenantChanged(ChangeEventArgs e)
{
try
private void TenantChanged(ChangeEventArgs e)
{
_tenantid = (string)e.Value;
if (_tenantid != "-1")
if (string.IsNullOrEmpty(_tenantname))
{
Tenant tenant = _tenants.Where(item => item.TenantId == int.Parse(_tenantid)).FirstOrDefault();
if (tenant != null)
{
_isinitialized = tenant.IsInitialized;
_tenantname = _name;
}
StateHasChanged();
}
}
}
catch (Exception ex)
private void SetIntegratedSecurity(ChangeEventArgs e)
{
await logger.LogError(ex, "Error Loading Tenant {TenantId} {Error}", _tenantid, ex.Message);
AddModuleMessage("Error Loading Tenant", MessageType.Error);
if (Convert.ToBoolean((string)e.Value))
{
_integratedsecurity = true;
}
else
{
_integratedsecurity = false;
}
StateHasChanged();
}
private async void ThemeChanged(ChangeEventArgs e)
@ -166,14 +265,18 @@ else
try
{
_themetype = (string)e.Value;
if (_themetype != "")
if (_themetype != "-")
{
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_panelayouts = new Dictionary<string, string>();
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containertype = "-";
StateHasChanged();
}
catch (Exception ex)
@ -185,99 +288,121 @@ else
private async Task SaveSite()
{
if (_tenantid != "-1" && _name != "" && _urls != "" && !string.IsNullOrEmpty(_themetype) && (_panelayouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)) && !string.IsNullOrEmpty(_containertype))
if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && (_layouts.Count == 0 || _layouttype != "-") && _containertype != "-" && _sitetemplatetype != "-")
{
bool unique = true;
List<Alias> aliases = await AliasService.GetAliasesAsync();
var duplicates = new List<string>();
var aliases = await AliasService.GetAliasesAsync();
foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
if (aliases.Exists(item => item.Name == name))
{
unique = false;
duplicates.Add(name);
}
}
if (unique)
{
bool isvalid = true;
if (!_isinitialized)
if (duplicates.Count == 0)
{
User user = new User();
InstallConfig config = new InstallConfig();
if (_tenantid == "+")
{
if (!string.IsNullOrEmpty(_tenantname) && _tenants.FirstOrDefault(item => item.Name == _tenantname) == null)
{
// validate host credentials
var user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = _username;
user.Password = _password;
user.Username = Constants.HostUser;
user.Password = _hostpassword;
user = await UserService.LoginUserAsync(user, false, false);
isvalid = user.IsAuthenticated;
}
if (isvalid)
if (user.IsAuthenticated)
{
ShowProgressIndicator();
aliases = new List<Alias>();
_urls = _urls.Replace("\n", ",");
foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
if (!string.IsNullOrEmpty(_server) && !string.IsNullOrEmpty(_database))
{
Alias alias = new Alias();
alias.Name = name;
alias.TenantId = int.Parse(_tenantid);
alias.SiteId = -1;
alias = await AliasService.AddAliasAsync(alias);
aliases.Add(alias);
}
Site site = new Site();
site.TenantId = int.Parse(_tenantid);
site.Name = _name;
site.LogoFileId = null;
site.DefaultThemeType = _themetype;
site.DefaultLayoutType = (_layouttype == null ? "" : _layouttype);
site.DefaultContainerType = _containertype;
site = await SiteService.AddSiteAsync(site, aliases[0]);
foreach (Alias alias in aliases)
var connectionString = string.Empty;
if (_databasetype == "LocalDB")
{
alias.SiteId = site.SiteId;
await AliasService.UpdateAliasAsync(alias);
}
if (!_isinitialized)
{
User user = new User();
user.SiteId = site.SiteId;
user.Username = _username;
user.Password = _password;
user.Email = PageState.User.Email;
user.DisplayName = PageState.User.DisplayName;
user = await UserService.AddUserAsync(user, aliases[0]);
if (user != null)
{
Tenant tenant = _tenants.FirstOrDefault(item => item.TenantId == int.Parse(_tenantid));
tenant.IsInitialized = true;
await TenantService.UpdateTenantAsync(tenant);
}
}
await Log(aliases[0], LogLevel.Information, "", null, "Site Created {Site}", site);
Uri uri = new Uri(NavigationManager.Uri);
NavigationManager.NavigateTo(uri.Scheme + "://" + aliases[0].Name, true);
connectionString = "Data Source=" + _server + ";AttachDbFilename=|DataDirectory|\\" + _database + ".mdf;Initial Catalog=" + _database + ";Integrated Security=SSPI;";
}
else
{
connectionString = "Data Source=" + _server + ";Initial Catalog=" + _database + ";";
if (_integratedsecurity)
{
connectionString += "Integrated Security=SSPI;";
}
else
{
connectionString += "User ID=" + _username + ";Password=" + _password;
}
}
config.ConnectionString = connectionString;
config.HostPassword = _hostpassword;
config.HostEmail = user.Email;
config.HostName = user.DisplayName;
config.TenantName = _tenantname;
config.IsNewTenant = true;
}
else
{
AddModuleMessage("You Must Specify A Server And Database", MessageType.Error);
}
}
else
{
await logger.LogError("Invalid Password Entered For Host {Username}", _username);
AddModuleMessage("Invalid Host Password", MessageType.Error);
}
}
else
{
AddModuleMessage("An Alias Specified Has Already Been Used For Another Site", MessageType.Warning);
AddModuleMessage("Tenant Name Is Missing Or Already Exists", MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Provide A Tenant, Site Name, Alias, And Default Theme/Container", MessageType.Warning);
var tenant = _tenants.FirstOrDefault(item => item.TenantId == int.Parse(_tenantid));
if (tenant != null)
{
config.TenantName = tenant.Name;
config.ConnectionString= tenant.DBConnectionString;
config.IsNewTenant = false;
}
}
if (!string.IsNullOrEmpty(config.TenantName))
{
config.SiteName = _name;
config.Aliases = _urls.Replace("\n", ",");
config.DefaultTheme = _themetype;
config.DefaultLayout = _layouttype;
config.DefaultContainer = _containertype;
config.SiteTemplate = _sitetemplatetype;
ShowProgressIndicator();
var installation = await InstallationService.Install(config);
if (installation.Success)
{
var aliasname = config.Aliases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
var uri = new Uri(NavigationManager.Uri);
NavigationManager.NavigateTo(uri.Scheme + "://" + aliasname, true);
}
else
{
await logger.LogError("Error Creating Site {Error}", installation.Message);
AddModuleMessage(installation.Message, MessageType.Error);
}
}
}
else
{
AddModuleMessage(string.Join(", ", duplicates.ToArray()) + " Already Used For Another Site", MessageType.Warning);
}
}
else
{
AddModuleMessage("You Must Provide A Tenant, Site Name, Alias, Default Theme/Container, And Site Template", MessageType.Warning);
}
}
}

View File

@ -11,83 +11,86 @@
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
<Label For="name" HelpText="Enter the name of the site">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@_name" />
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Tenant: </label>
<Label For="tenant" HelpText="Enter the tenant for the site">Tenant: </Label>
</td>
<td>
<input class="form-control" @bind="@_tenant" readonly />
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
</td>
</tr>
<tr>
<td>
<label class="control-label">Aliases: </label>
<Label For="alias" HelpText="Enter the alias for the server">Aliases: </Label>
</td>
<td>
<textarea class="form-control" @bind="@_urls" rows="3" />
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Default Theme: </label>
<Label For="defaultTheme" HelpText="Select the default theme for the website">Default Theme: </Label>
</td>
<td>
<select class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in _themes)
<select id="defaultTheme" class="form-control" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;Select Theme&gt;</option>
@foreach (var theme in _themes)
{
if (item.Key == _themetype)
if (theme.TypeName == _themetype)
{
<option value="@item.Key" selected>@item.Value</option>
<option value="@theme.TypeName" selected>@theme.Name</option>
}
else
{
<option value="@item.Key">@item.Value</option>
<option value="@theme.TypeName">@theme.Name</option>
}
}
</select>
</td>
</tr>
<tr>
<td>
<label class="control-label">Default Layout: </label>
</td>
<td>
<select class="form-control" @bind="@_layouttype">
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in _panelayouts)
@if (_layouts.Count > 0)
{
<option value="@panelayout.Key">@panelayout.Value</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label class="control-label">Default Container: </label>
<Label For="defaultLayout" HelpText="Select the default layout for the site">Default Layout: </Label>
</td>
<td>
<select class="form-control" @bind="@_containertype">
<option value="">&lt;Select Container&gt;</option>
@foreach (KeyValuePair<string, string> container in _containers)
<select id="defaultLayout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;Select Layout&gt;</option>
@foreach (var layout in _layouts)
{
<option value="@container.Key">@container.Value</option>
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the site">Default Container: </Label>
</td>
<td>
<select id="defaultIdea" class="form-control" @bind="@_containertype">
<option value="-">&lt;Select Container&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<label class="control-label">Is Deleted? </label>
<Label For="isDeleted" HelpText="Has this site been deleted?">Is Deleted? </Label>
</td>
<td>
<select class="form-control" @bind="@_isdeleted">
<select id="isDeleted" class="form-control" @bind="@_isdeleted">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -103,30 +106,28 @@
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private Alias _alias;
private string _name = string.Empty;
private List<Tenant> _tenantList;
private string _tenant = string.Empty;
private List<Alias> _aliasList;
private string _urls = string.Empty;
private string _themetype;
private string _layouttype;
private string _containertype;
private string _createdby;
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
private string _deletedby;
private DateTime? _deletedon;
private string _isdeleted;
Dictionary<string, string> _themes;
Dictionary<string, string> _panelayouts;
Dictionary<string, string> _containers;
Alias _alias;
List<Theme> _themeList;
string _name = "";
List<Tenant> _tenantList;
string _tenant = "";
List<Alias> _aliasList;
string _urls = "";
string _themetype;
string _layouttype;
string _containertype;
string _createdby;
DateTime _createdon;
string _modifiedby;
DateTime _modifiedon;
string _deletedby;
DateTime? _deletedon;
string _isdeleted;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
@ -136,21 +137,25 @@
_aliasList = await AliasService.GetAliasesAsync();
_alias = _aliasList.Find(item => item.AliasId == Int32.Parse(PageState.QueryString["id"]));
Site site = await SiteService.GetSiteAsync(_alias.SiteId, _alias);
SiteService.SetAlias(_alias);
var site = await SiteService.GetSiteAsync(_alias.SiteId);
if (site != null)
{
_name = site.Name;
_tenantList = await TenantService.GetTenantsAsync();
_tenant = _tenantList.Find(item => item.TenantId == site.TenantId).Name;
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
{
_urls += alias.Name + "\n";
}
_themetype = site.DefaultThemeType;
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_layouttype = site.DefaultLayoutType;
_containertype = site.DefaultContainerType;
_themes = ThemeService.GetThemeControls(_themeList);
_themetype = site.DefaultThemeType;
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_layouttype = site.DefaultLayoutType;
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = site.DefaultContainerType;
_createdby = site.CreatedBy;
_createdon = site.CreatedOn;
_modifiedby = site.ModifiedBy;
@ -159,13 +164,10 @@
_deletedon = site.DeletedOn;
_isdeleted = site.IsDeleted.ToString();
}
_themes = ThemeService.GetThemeTypes(_themeList);
_containers = ThemeService.GetContainerTypes(_themeList);
}
catch (Exception ex)
{
await Log(_alias, LogLevel.Error, "", ex, "Error Loading Site {SiteId} {Error}", _alias.SiteId, ex.Message);
await Log(_alias, LogLevel.Error, string.Empty, ex, "Error Loading Site {SiteId} {Error}", _alias.SiteId, ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
}
}
@ -175,14 +177,18 @@
try
{
_themetype = (string)e.Value;
if (_themetype != "")
if (_themetype != "-")
{
_panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype);
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_panelayouts = new Dictionary<string, string>();
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containertype = "-";
StateHasChanged();
}
catch (Exception ex)
@ -196,9 +202,9 @@
{
try
{
if (_name != "" && _urls != "" && !string.IsNullOrEmpty(_themetype) && (_panelayouts.Count == 0 || !string.IsNullOrEmpty(_layouttype)) && !string.IsNullOrEmpty(_containertype))
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && (_layouts.Count == 0 || _layouttype != "-") && _containertype != "-")
{
bool unique = true;
var unique = true;
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
if (_aliasList.Exists(item => item.Name == name && item.SiteId != _alias.SiteId && item.TenantId != _alias.TenantId))
@ -206,22 +212,25 @@
unique = false;
}
}
if (unique)
{
Site site = await SiteService.GetSiteAsync(_alias.SiteId, _alias);
SiteService.SetAlias(_alias);
var site = await SiteService.GetSiteAsync(_alias.SiteId);
if (site != null)
{
site.Name = _name;
site.LogoFileId = null;
site.DefaultThemeType = _themetype;
site.DefaultLayoutType = _layouttype ?? "";
site.DefaultLayoutType = _layouttype ?? string.Empty;
site.DefaultContainerType = _containertype;
site.IsDeleted = (_isdeleted == null || Boolean.Parse(_isdeleted));
site = await SiteService.UpdateSiteAsync(site, _alias);
site = await SiteService.UpdateSiteAsync(site);
_urls = _urls.Replace("\n", ",");
string[] names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
{
if (!names.Contains(alias.Name))
@ -229,6 +238,7 @@
await AliasService.DeleteAliasAsync(alias.AliasId);
}
}
foreach (string name in names)
{
if (!_aliasList.Exists(item => item.Name == name))
@ -260,7 +270,7 @@
}
catch (Exception ex)
{
await Log(_alias, LogLevel.Error, "", ex, "Error Saving Site {SiteId} {Error}", _alias.SiteId, ex.Message);
await Log(_alias, LogLevel.Error, string.Empty, ex, "Error Saving Site {SiteId} {Error}", _alias.SiteId, ex.Message);
AddModuleMessage("Error Saving Site", MessageType.Error);
}
}

View File

@ -14,8 +14,8 @@ else
<Pager Items="@_sites">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
</Header>
<Row>
@ -27,17 +27,17 @@ else
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<Alias> _sites;
private string _scheme;
List<Alias> _sites;
string _scheme;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnParametersSetAsync()
{
Uri uri = new Uri(NavigationManager.Uri);
var uri = new Uri(NavigationManager.Uri);
_scheme = uri.Scheme + "://";
List<Alias> aliases = await AliasService.GetAliasesAsync();
var aliases = await AliasService.GetAliasesAsync();
_sites = new List<Alias>();
foreach (Alias alias in aliases)
{
@ -54,13 +54,16 @@ else
{
if (alias.SiteId != PageState.Site.SiteId || alias.TenantId != PageState.Site.TenantId)
{
await SiteService.DeleteSiteAsync(alias.SiteId, alias);
SiteService.SetAlias(alias);
await SiteService.DeleteSiteAsync(alias.SiteId);
await Log(alias, LogLevel.Information, "", null, "Site Deleted {SiteId}", alias.SiteId);
List<Alias> aliases = await AliasService.GetAliasesAsync();
var aliases = await AliasService.GetAliasesAsync();
foreach (Alias a in aliases.Where(item => item.SiteId == alias.SiteId && item.TenantId == alias.TenantId))
{
await AliasService.DeleteAliasAsync(a.AliasId);
}
NavigationManager.NavigateTo(NavigateUrl());
}
else

View File

@ -0,0 +1,111 @@
@namespace Oqtane.Modules.Admin.Sql
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ITenantService TenantService
@inject ISqlService SqlService
@if (_tenants == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table table-borderless">
<tr>
<td>
<Label For="tenant" HelpText="Select the tenant for the SQL server">Tenant: </Label>
</td>
<td>
<select id="teneant" class="form-control" @bind="_tenantid">
<option value="-1">&lt;Select Tenant&gt;</option>
@foreach (Tenant tenant in _tenants)
{
<option value="@tenant.TenantId">@tenant.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="sqlQeury" HelpText="Enter the query for the SQL server">SQL Query: </Label>
</td>
<td>
<textarea id="sqlQeury" class="form-control" @bind="@_sql" rows="5"></textarea>
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="Execute">Execute</button>
<br /><br />
@if (!string.IsNullOrEmpty(_results))
{
@((MarkupString)_results)
}
}
@code {
private List<Tenant> _tenants;
private string _tenantid = "-1";
private string _sql = string.Empty;
private string _results = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
_tenants = await TenantService.GetTenantsAsync();
}
private async Task Execute()
{
if (_tenantid != "-1" && !string.IsNullOrEmpty(_sql))
{
var sqlquery = new SqlQuery { TenantId = int.Parse(_tenantid), Query = _sql };
sqlquery = await SqlService.ExecuteQueryAsync(sqlquery);
_results = DisplayResults(sqlquery.Results);
}
else
{
AddModuleMessage("You Must Select A Tenant And Provide A SQL Query", MessageType.Warning);
}
}
private string DisplayResults(List<Dictionary<string, string>> results)
{
var table = string.Empty;
foreach (Dictionary<string, string> item in results)
{
if (table == string.Empty)
{
table = "<div class=\"table-responsive\">";
table += "<table class=\"table table-bordered\"><thead><tr>";
foreach (KeyValuePair<string, string> kvp in item)
{
table += "<th scope=\"col\">" + kvp.Key + "</th>";
}
table += "</tr></thead><tbody>";
}
table += "<tr>";
foreach (KeyValuePair<string, string> kvp in item)
{
table += "<td>" + kvp.Value + "</td>";
}
table += "</tr>";
}
if (table != string.Empty)
{
table += "</tbody></table></div>";
}
else
{
table = "No Results Returned";
}
return table;
}
}

View File

@ -0,0 +1,81 @@
@namespace Oqtane.Modules.Admin.SystemInfo
@inherits ModuleBase
@inject ISystemService SystemService
<table class="table table-borderless">
<tr>
<td>
<Label For="version" HelpText="Framework Version">Framework Version: </Label>
</td>
<td>
<input id="version" class="form-control" @bind="@_version" readonly />
</td>
</tr>
<tr>
<td>
<Label For="runtime" HelpText="Blazor Runtime (Server or WebAssembly)">Blazor Runtime: </Label>
</td>
<td>
<input id="runtime" class="form-control" @bind="@_runtime" readonly />
</td>
</tr>
<tr>
<td>
<Label For="clrversion" HelpText="Common Language Runtime Version">CLR Version: </Label>
</td>
<td>
<input id="clrversion" class="form-control" @bind="@_clrversion" readonly />
</td>
</tr>
<tr>
<td>
<Label For="osversion" HelpText="Operating System Version">OS Version: </Label>
</td>
<td>
<input id="osversion" class="form-control" @bind="@_osversion" readonly />
</td>
</tr>
<tr>
<td>
<Label For="serverpath" HelpText="Server Path">Server Path: </Label>
</td>
<td>
<input id="serverpath" class="form-control" @bind="@_serverpath" readonly />
</td>
</tr>
<tr>
<td>
<Label For="servertime" HelpText="Server Time">Server Time: </Label>
</td>
<td>
<input id="servertime" class="form-control" @bind="@_servertime" readonly />
</td>
</tr>
</table>
<a class="btn btn-primary" href="swagger/index.html" target="_new">Access Framework API</a>
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
private string _version = string.Empty;
private string _runtime = string.Empty;
private string _clrversion = string.Empty;
private string _osversion = string.Empty;
private string _serverpath = string.Empty;
private string _servertime = string.Empty;
protected override async Task OnInitializedAsync()
{
_version = Constants.Version;
_runtime = PageState.Runtime.ToString();
Dictionary<string, string> systeminfo = await SystemService.GetSystemInfoAsync();
if (systeminfo != null)
{
_clrversion = systeminfo["clrversion"];
_osversion = systeminfo["osversion"];
_serverpath = systeminfo["serverpath"];
_servertime = systeminfo["servertime"];
}
}
}

View File

@ -1,154 +0,0 @@
@namespace Oqtane.Modules.Admin.Tenants
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ITenantService TenantService
@inject IInstallationService InstallationService
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" />
</td>
</tr>
<tr>
<td>
<label for="Title" class="control-label">Database Type: </label>
</td>
<td>
<select class="custom-select" @bind="@type">
<option value="LocalDB">Local Database</option>
<option value="SQLServer">SQL Server</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="Title" class="control-label">Server: </label>
</td>
<td>
<input type="text" class="form-control" @bind="@server" />
</td>
</tr>
<tr>
<td>
<label for="Title" class="control-label">Database: </label>
</td>
<td>
<input type="text" class="form-control" @bind="@database" />
</td>
</tr>
<tr>
<td>
<label for="Title" class="control-label">Integrated Security: </label>
</td>
<td>
<select class="custom-select" @onchange="SetIntegratedSecurity">
<option value="true" selected>True</option>
<option value="false">False</option>
</select>
</td>
</tr>
<tr style="@integratedsecurity">
<td>
<label for="Title" class="control-label">Username: </label>
</td>
<td>
<input type="text" class="form-control" @bind="@username" />
</td>
</tr>
<tr style="@integratedsecurity">
<td>
<label for="Title" class="control-label">Password: </label>
</td>
<td>
<input type="password" class="form-control" @bind="@password" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Schema: </label>
</td>
<td>
<input class="form-control" @bind="@schema" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveTenant">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
string name = "";
string type = "LocalDB";
string server = "(LocalDb)\\MSSQLLocalDB";
string database = "Oqtane-" + DateTime.UtcNow.ToString("yyyyMMddHHmm");
string username = "";
string password = "";
string schema = "";
string integratedsecurity = "display: none;";
private void SetIntegratedSecurity(ChangeEventArgs e)
{
if (Convert.ToBoolean((string)e.Value))
{
integratedsecurity = "display: none;";
}
else
{
integratedsecurity = "";
}
}
private async Task SaveTenant()
{
if (!string.IsNullOrEmpty(name))
{
ShowProgressIndicator();
string connectionstring = "";
if (type == "LocalDB")
{
connectionstring = "Data Source=" + server + ";AttachDbFilename=|DataDirectory|\\" + database + ".mdf;Initial Catalog=" + database + ";Integrated Security=SSPI;";
}
else
{
connectionstring = "Data Source=" + server + ";Initial Catalog=" + database + ";";
if (integratedsecurity == "display: none;")
{
connectionstring += "Integrated Security=SSPI;";
}
else
{
connectionstring += "User ID=" + username + ";Password=" + password;
}
}
GenericResponse response = await InstallationService.Install(connectionstring);
if (response.Success)
{
Tenant tenant = new Tenant();
tenant.Name = name;
tenant.DBConnectionString = connectionstring;
tenant.DBSchema = schema;
tenant.IsInitialized = false;
await TenantService.AddTenantAsync(tenant);
await logger.LogInformation("Tenant Created {Tenant}", tenant);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
await logger.LogError("Error Creating Tenant {Error}", response.Message);
AddModuleMessage(response.Message, MessageType.Error);
}
}
else
{
AddModuleMessage("You Must Provide A Name For The Tenant", MessageType.Warning);
}
}
}

View File

@ -6,51 +6,50 @@
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Name: </label>
<Label For="name" HelpText="The name of the tenant">Name: </Label>
</td>
<td>
<input class="form-control" @bind="@name" />
@if (name == Constants.MasterTenant)
{
<input id="name" class="form-control" @bind="@name" readonly />
}
else
{
<input id="name" class="form-control" @bind="@name" />
}
</td>
</tr>
<tr>
<td>
<label class="control-label">Connection String: </label>
<Label For="connectionstring" HelpText="The database connection string">Connection String: </Label>
</td>
<td>
<input class="form-control" @bind="@connectionstring" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Schema: </label>
</td>
<td>
<input class="form-control" @bind="@schema" />
<textarea id="connectionstring" class="form-control" @bind="@connectionstring" rows="3" readonly></textarea>
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveTenant">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private int tenantid;
private string name = string.Empty;
private string connectionstring = string.Empty;
private string schema = string.Empty;
int tenantid;
string name = "";
string connectionstring = "";
string schema = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
try
{
tenantid = Int32.Parse(PageState.QueryString["id"]);
Tenant tenant = await TenantService.GetTenantAsync(tenantid);
var tenant = await TenantService.GetTenantAsync(tenantid);
if (tenant != null)
{
name = tenant.Name;
connectionstring = tenant.DBConnectionString;
schema = tenant.DBSchema;
}
}
catch (Exception ex)
@ -65,12 +64,12 @@
try
{
connectionstring = connectionstring.Replace("\\\\", "\\");
Tenant tenant = await TenantService.GetTenantAsync(tenantid);
var tenant = await TenantService.GetTenantAsync(tenantid);
if (tenant != null)
{
tenant.Name = name;
tenant.DBConnectionString = connectionstring;
tenant.DBSchema = schema;
await TenantService.UpdateTenantAsync(tenant);
await logger.LogInformation("Tenant Saved {TenantId}", tenantid);

View File

@ -1,6 +1,7 @@
@namespace Oqtane.Modules.Admin.Tenants
@inherits ModuleBase
@inject ITenantService TenantService
@inject IAliasService AliasService
@if (tenants == null)
{
@ -8,17 +9,15 @@
}
else
{
<ActionLink Action="Add" Text="Add Tenant" />
<Pager Items="@tenants">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.TenantId.ToString())" /></td>
<td><ActionDialog Header="Delete Tenant" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Tenant?")" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteTenant(context))" /></td>
<td><ActionDialog Header="Delete Tenant" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Tenant?")" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteTenant(context))" Disabled="@(context.Name == Constants.MasterTenant)" /></td>
<td>@context.Name</td>
</Row>
</Pager>
@ -26,9 +25,9 @@ else
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<Tenant> tenants;
List<Tenant> tenants;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnParametersSetAsync()
{
@ -38,11 +37,27 @@ else
private async Task DeleteTenant(Tenant Tenant)
{
try
{
string message = string.Empty;
var aliases = await AliasService.GetAliasesAsync();
foreach (var alias in aliases)
{
if (alias.TenantId == Tenant.TenantId)
{
message += ", " + alias.Name;
}
}
if (string.IsNullOrEmpty(message))
{
await TenantService.DeleteTenantAsync(Tenant.TenantId);
await logger.LogInformation("Tenant Deleted {Tenant}", Tenant);
StateHasChanged();
}
else
{
AddModuleMessage("Tenant Cannot Be Deleted Until The Following Sites Are Deleted: " + message.Substring(2), MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Tenant {Tenant} {Error}", Tenant, ex.Message);

View File

@ -5,69 +5,102 @@
@inject IThemeService ThemeService
@inject IPackageService PackageService
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Theme: </label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Themes" />
</td>
</tr>
</table>
@if (packages != null)
@if (_packages != null)
{
<hr class="app-rule" />
<div class="mx-auto text-center"><h2>Available Themes</h2></div>
<Pager Items="@packages">
<TabStrip>
@if (_packages.Count > 0)
{
<TabPanel Name="Download">
<ModuleMessage Type="MessageType.Info" Message="Download one or more themes from the list below. Once you are ready click Install to complete the installation."></ModuleMessage>
<Pager Items="@_packages">
<Header>
<th>Name</th>
<th>Version</th>
<th></th>
<th style="width: 1px;"></th>
</Header>
<Row>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadTheme(context.PackageId, context.Version))>Download Theme</button>
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadTheme(context.PackageId, context.Version))>Download</button>
</td>
</Row>
</Pager>
</TabPanel>
}
<TabPanel Name="Upload">
<table class="table table-borderless">
<tr>
<td>
<Label HelpText="Upload one or more theme packages. Once they are uploaded click Install to complete the installation.">Theme: </Label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Themes" UploadMultiple="@true" />
</td>
</tr>
</table>
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="InstallThemes">Install</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
<button type="button" class="btn btn-success" @onclick="InstallThemes">Install</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<Package> _packages;
List<Package> packages;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
List<Theme> themes = await ThemeService.GetThemesAsync();
packages = await PackageService.GetPackagesAsync("theme");
foreach(Package package in packages.ToArray())
try
{
var themes = await ThemeService.GetThemesAsync();
_packages = await PackageService.GetPackagesAsync("theme");
foreach (Package package in _packages.ToArray())
{
if (themes.Exists(item => Utilities.GetTypeName(item.ThemeName) == package.PackageId))
{
packages.Remove(package);
_packages.Remove(package);
}
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Packages {Error}", ex.Message);
AddModuleMessage("Error Loading Packages", MessageType.Error);
}
}
private async Task InstallThemes()
{
try
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await ThemeService.InstallThemesAsync();
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Installating Theme");
}
}
private async Task DownloadTheme(string packageid, string version)
{
try
{
await PackageService.DownloadPackageAsync(packageid, version, "Themes");
AddModuleMessage("Theme Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success);
await logger.LogInformation("Theme {ThemeName} {Version} Downloaded Successfully", packageid, version);
AddModuleMessage("Themes Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Module {ThemeName} {Version}", packageid, version);
AddModuleMessage("Error Downloading Theme", MessageType.Error);
}
}
}

View File

@ -1,10 +1,11 @@
@namespace Oqtane.Modules.Admin.Themes
@using System.Net
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IThemeService ThemeService
@inject IPackageService PackageService
@if (themes == null)
@if (_themes == null)
{
<p><em>Loading...</em></p>
}
@ -12,14 +13,16 @@ else
{
<ActionLink Action="Add" Text="Install Theme" />
<Pager Items="@themes">
<Pager Items="@_themes">
<Header>
<th>&nbsp;</th>
<th>Name</th>
<th>Version</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th scope="col">Name</th>
<th scope="col">Version</th>
<th>&nbsp;</th>
</Header>
<Row>
<td><ActionLink Action="View" Parameters="@($"name=" + WebUtility.UrlEncode(context.ThemeName))" /></td>
<td>
@if (context.AssemblyName != "Oqtane.Client")
{
@ -34,45 +37,79 @@ else
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadTheme(context.ThemeName, context.Version))>Upgrade</button>
}
</td>
<td></td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private List<Theme> _themes;
private List<Package> _packages;
List<Theme> themes;
List<Package> packages;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
themes = await ThemeService.GetThemesAsync();
packages = await PackageService.GetPackagesAsync("module");
try
{
_themes = await ThemeService.GetThemesAsync();
_packages = await PackageService.GetPackagesAsync("theme");
}
catch (Exception ex)
{
if (_themes == null)
{
await logger.LogError(ex, "Error Loading Themes {Error}", ex.Message);
AddModuleMessage("Error Loading Themes", MessageType.Error);
}
}
}
private bool UpgradeAvailable(string themename, string version)
{
bool upgradeavailable = false;
Package package = packages.Where(item => item.PackageId == Utilities.GetTypeName(themename)).FirstOrDefault();
var upgradeavailable = false;
if (_packages != null)
{
var package = _packages.Where(item => item.PackageId == Utilities.GetTypeName(themename)).FirstOrDefault();
if (package != null)
{
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
}
}
return upgradeavailable;
}
private async Task DownloadTheme(string themename, string version)
{
try
{
await PackageService.DownloadPackageAsync(themename, version, "Themes");
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", themename, version);
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await ThemeService.InstallThemesAsync();
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Theme {ThemeName} {Version} {Error}", themename, version, ex.Message);
AddModuleMessage("Error Downloading Theme", MessageType.Error);
}
}
private async Task DeleteTheme(Theme Theme)
{
try
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await ThemeService.DeleteThemeAsync(Theme.ThemeName);
await logger.LogInformation("Theme Deleted {Theme}", Theme);
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Theme {Theme} {Error}", Theme, ex.Message);
AddModuleMessage("Error Deleting Theme", MessageType.Error);
}
}
}

View File

@ -0,0 +1,101 @@
@namespace Oqtane.Modules.Admin.Themes
@using System.Net
@inherits ModuleBase
@inject IThemeService ThemeService
@inject NavigationManager NavigationManager
<table class="table table-borderless">
<tr>
<td>
<Label For="name" HelpText="The name of the theme">Name: </Label>
</td>
<td>
<input id="name" class="form-control" @bind="@_name" disabled />
</td>
</tr>
<tr>
<td>
<Label For="themename" HelpText="The internal name of the module">Internal Name: </Label>
</td>
<td>
<input id="themename" class="form-control" @bind="@_themeName" disabled />
</td>
</tr>
<tr>
<td>
<Label For="version" HelpText="The version of the thene">Version: </Label>
</td>
<td>
<input id="version" class="form-control" @bind="@_version" disabled />
</td>
</tr>
<tr>
<td>
<Label For="owner" HelpText="The owner or creator of the theme">Owner: </Label>
</td>
<td>
<input id="owner" class="form-control" @bind="@_owner" disabled />
</td>
</tr>
<tr>
<td>
<Label For="url" HelpText="The reference url of the theme">Reference Url: </Label>
</td>
<td>
<input id="url" class="form-control" @bind="@_url" disabled />
</td>
</tr>
<tr>
<td>
<Label For="contact" HelpText="The contact for the theme">Contact: </Label>
</td>
<td>
<input id="contact" class="form-control" @bind="@_contact" disabled />
</td>
</tr>
<tr>
<td>
<Label For="license" HelpText="The license of the theme">License: </Label>
</td>
<td>
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
</td>
</tr>
</table>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
private string _themeName = "";
private string _name;
private string _version;
private string _owner = "";
private string _url = "";
private string _contact = "";
private string _license = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
try
{
_themeName = WebUtility.UrlDecode(PageState.QueryString["name"]);
var themes = await ThemeService.GetThemesAsync();
var theme = themes.FirstOrDefault(item => item.ThemeName == _themeName);
if (theme != null)
{
_name = theme.Name;
_version = theme.Version;
_owner = theme.Owner;
_url = theme.Url;
_contact = theme.Contact;
_license = theme.License;
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Theme {ThemeName} {Error}", _themeName, ex.Message);
AddModuleMessage("Error Loading Theme", MessageType.Error);
}
}
}

View File

@ -5,55 +5,96 @@
@inject IPackageService PackageService
@inject IInstallationService InstallationService
<table class="table table-borderless">
@if (_package != null)
{
<TabStrip>
<TabPanel Name="Download">
@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>
}
else
{
<ModuleMessage Type="MessageType.Info" Message="Framework Is Already Up To Date"></ModuleMessage>
}
</TabPanel>
<TabPanel Name="Upload">
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Framework: </label>
<Label HelpText="Upload a framework package and select Install to complete the installation">Framework: </Label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Framework" />
<FileManager Filter="nupkg" Folder="Framework" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="Upgrade">Upgrade</button>
@if (upgradeavailable)
{
<hr class="app-rule" />
<div class="mx-auto text-center"><h2>Upgrade Available</h2></div>
<button type="button" class="btn btn-success" @onclick=@(async () => await Download(Constants.PackageId, Constants.Version))>Upgrade Framework</button>
</table>
<button type="button" class="btn btn-success" @onclick="Upgrade">Install</button>
</TabPanel>
</TabStrip>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
private Package _package;
private bool _upgradeavailable = false;
bool upgradeavailable = false;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
try
{
List<Package> packages = await PackageService.GetPackagesAsync("framework");
Package package = packages.FirstOrDefault();
if (package != null)
if (packages != null)
{
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
_package = packages.FirstOrDefault();
if (_package != null)
{
_upgradeavailable = (Version.Parse(_package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
}
if (!upgradeavailable)
else
{
AddModuleMessage("Framework Is Up To Date", MessageType.Info);
_package = new Package { Name = Constants.PackageId, Version = Constants.Version };
}
}
}
catch
{
// can be caused by no network connection
}
}
private async Task Upgrade()
{
try
{
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await InstallationService.Upgrade();
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Executing Upgrade {Error}", ex.Message);
AddModuleMessage("Error Executing Upgrade", MessageType.Error);
}
}
private async Task Download(string packageid, string version)
{
try
{
await PackageService.DownloadPackageAsync(packageid, version, "Framework");
ShowProgressIndicator();
var interop = new Interop(JSRuntime);
await interop.RedirectBrowser(NavigateUrl(), 3);
await InstallationService.Upgrade();
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Framework {Error}", ex.Message);
AddModuleMessage("Error Downloading Framework", MessageType.Error);
}
}
}

View File

@ -1,7 +1,7 @@
@namespace Oqtane.Modules.Admin.UserProfile
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IUserRoleService UserRoleService
@inject IUserService UserService
@inject INotificationService NotificationService
@if (PageState.User != null)
@ -9,35 +9,26 @@
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">To: </label>
<Label For="to" HelpText="Enter the username you wish to send a message to">To: </Label>
</td>
<td>
<select class="form-control" @bind="@userid">
<option value="-1">&lt;Select User&gt;</option>
@if (userroles != null)
{
foreach (UserRole userrole in userroles)
{
<option value="@userrole.UserId">@userrole.User.DisplayName</option>
}
}
</select>
<input id="to" class="form-control" @bind="@username" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Subject: </label>
<Label For="subject" HelpText="Enter the subject of the message">Subject: </Label>
</td>
<td>
<input class="form-control" @bind="@subject" />
<input id="subject" class="form-control" @bind="@subject" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Message: </label>
<Label For="message" HelpText="Enter the message">Message: </Label>
</td>
<td>
<textarea class="form-control" @bind="@body" rows="5" />
<textarea id="message" class="form-control" @bind="@body" rows="5" />
</td>
</tr>
</table>
@ -46,50 +37,45 @@
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } }
public override string Title { get { return "Send Notification"; } }
private string username = "";
private string subject = "";
private string body = "";
List<UserRole> userroles;
string userid = "-1";
string subject = "";
string body = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
protected override async Task OnInitializedAsync()
{
try
{
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
userroles = userroles.Where(item => item.Role.Name == Constants.RegisteredRole || item.Role.Name == Constants.HostRole)
.OrderBy(item => item.User.DisplayName).ToList();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Users {Error}", ex.Message);
AddModuleMessage("Error Loading Users", MessageType.Error);
}
}
public override string Title => "Send Notification";
private async Task Send()
{
Notification notification = new Notification();
var notification = new Notification();
try
{
var user = await UserService.GetUserAsync(username, PageState.Site.SiteId);
if (user != null)
{
notification.SiteId = PageState.Site.SiteId;
notification.FromUserId = PageState.User.UserId;
notification.ToUserId = int.Parse(userid);
notification.ToEmail = "";
notification.FromDisplayName = PageState.User.DisplayName;
notification.FromEmail = PageState.User.Email;
notification.ToUserId = user.UserId;
notification.ToDisplayName = user.DisplayName;
notification.ToEmail = user.Email;
notification.Subject = subject;
notification.Body = body;
notification.ParentId = null;
notification.CreatedOn = DateTime.UtcNow;
notification.IsDelivered = false;
notification.DeliveredOn = null;
notification.SendOn = DateTime.UtcNow;
notification = await NotificationService.AddNotificationAsync(notification);
await logger.LogInformation("Notification Created {Notification}", notification);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage("User Does Not Exist. Please Verify That The Username Provided Is Correct.", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Adding Notification {Notification} {Error}", notification, ex.Message);

View File

@ -6,34 +6,18 @@
@inject ISettingService SettingService
@inject INotificationService NotificationService
@if (PageState.User != null && profiles != null)
@if (PageState.User != null && photofileid != -1)
{
<div class="container-fluid">
<div class="form-group">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#Profile" role="tab">
Profile
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#Notifications" role="tab">
Notifications
</a>
</li>
</ul>
<div class="tab-content">
<div id="Profile" class="tab-pane fade show active" role="tabpanel">
@if (photofileid != -1)
{
<img src="@(ContentUrl(photofileid))" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
}
else
{
}
else
{
<br />
}
}
<TabStrip>
<TabPanel Name="Identity">
@if (PageState.User != null)
{
<table class="table table-borderless">
<tr>
<td>
@ -48,7 +32,7 @@
<label for="Name" class="control-label">Password: </label>
</td>
<td>
<input type="password" class="form-control" @bind="@password" />
<input type="password" class="form-control" @bind="@password" autocomplete="new-password" />
</td>
</tr>
<tr>
@ -56,7 +40,7 @@
<label for="Name" class="control-label">Confirm Password: </label>
</td>
<td>
<input type="password" class="form-control" @bind="@confirm" />
<input type="password" class="form-control" @bind="@confirm" autocomplete="new-password" />
</td>
</tr>
<tr>
@ -80,10 +64,18 @@
<label for="Name" class="control-label">Photo: </label>
</td>
<td>
<FileManager FileId="@photofileid.ToString()" @ref="filemanager" />
<FileManager FileId="@photofileid" @ref="filemanager" />
</td>
</tr>
</table>
<button type="button" class="btn btn-primary" @onclick="Save">Save</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
}
</TabPanel>
<TabPanel Name="Profile">
@if (profiles != null && settings != null)
{
<table class="table table-borderless">
@foreach (Profile profile in profiles)
{
var p = profile;
@ -108,18 +100,19 @@
</table>
<button type="button" class="btn btn-primary" @onclick="Save">Save</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
</div>
<div id="Notifications" class="tab-pane fade" role="tabpanel">
<br />
}
</TabPanel>
<TabPanel Name="Notifications">
@if (notifications != null)
{
<ActionLink Action="Add" Text="Send Notification" Security="SecurityAccessLevel.View" EditMode="false" />
<br /><br />
@if (filter == "to")
{
<Pager Items="@notifications">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>From</th>
<th>Subject</th>
<th>Received</th>
@ -127,13 +120,22 @@
<Row>
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" /></td>
<td><ActionDialog Header="Delete Notification" Message="@("Are You Sure You Wish To Delete This Notification?")" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" /></td>
<td>@(context.FromUser == null ? "System" : context.FromUser.DisplayName)</td>
<td>@context.FromDisplayName</td>
<td>@context.Subject</td>
<td>@context.CreatedOn</td>
</Row>
<Detail>
<td colspan="2"></td>
<td colspan="3">@(context.Body.Length > 100 ? context.Body.Substring(0,100) : context.Body)</td>
<td colspan="3">
@{
string input = "___";
if (context.Body.Contains(input)){
context.Body = context.Body.Split(input)[0];
context.Body = context.Body.Replace("\n", "");
context.Body = context.Body.Replace("\r", "");
} }
@(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body)
</td>
</Detail>
</Pager>
}
@ -150,13 +152,22 @@
<Row>
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" /></td>
<td><ActionDialog Header="Delete Notification" Message="@("Are You Sure You Wish To Delete This Notification?")" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" /></td>
<td>@(context.ToUser == null ? context.ToEmail : context.ToUser.DisplayName)</td>
<td>@context.ToDisplayName</td>
<td>@context.Subject</td>
<td>@context.CreatedOn</td>
</Row>
<Detail>
<td colspan="2"></td>
<td colspan="3">@(context.Body.Length > 100 ? context.Body.Substring(0,100) : context.Body)</td>
<td colspan="3">
@{
string input = "___";
if (context.Body.Contains(input)){
context.Body = context.Body.Split(input)[0];
context.Body = context.Body.Replace("\n", "");
context.Body = context.Body.Replace("\r", "");
} }
@(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body)
</td>
</Detail>
</Pager>
}
@ -165,27 +176,25 @@
<option value="to">Inbox</option>
<option value="from">Sent Items</option>
</select>
</div>
</div>
</div>
</div>
}
}
</TabPanel>
</TabStrip>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } }
private string username = string.Empty;
private string password = string.Empty;
private string confirm = string.Empty;
private string email = string.Empty;
private string displayname = string.Empty;
private FileManager filemanager;
private int photofileid = -1;
private List<Profile> profiles;
private Dictionary<string, string> settings;
private string category = string.Empty;
private string filter = "to";
private List<Notification> notifications;
string username = "";
string password = "";
string confirm = "";
string email = "";
string displayname = "";
FileManager filemanager;
int photofileid = -1;
List<Profile> profiles;
Dictionary<string, string> settings;
string category = "";
string filter = "to";
List<Notification> notifications;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
protected override async Task OnInitializedAsync()
{
@ -196,12 +205,15 @@
username = PageState.User.Username;
email = PageState.User.Email;
displayname = PageState.User.DisplayName;
if (PageState.User.PhotoFileId != null)
{
photofileid = PageState.User.PhotoFileId.Value;
}
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
await LoadNotificationsAsync();
}
else
@ -223,29 +235,29 @@
}
private string GetProfileValue(string SettingName, string DefaultValue)
{
return SettingService.GetSetting(settings, SettingName, DefaultValue);
}
=> SettingService.GetSetting(settings, SettingName, DefaultValue);
private async Task Save()
{
try
{
if (username != "" && email != "")
if (username != string.Empty && email != string.Empty)
{
if (password == confirm)
{
User user = PageState.User;
var user = PageState.User;
user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = (displayname == "" ? username : displayname);
user.DisplayName = (displayname == string.Empty ? username : displayname);
user.PhotoFileId = null;
photofileid = filemanager.GetFileId();
if (photofileid != -1)
{
user.PhotoFileId = photofileid;
}
await UserService.UpdateUserAsync(user);
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
await logger.LogInformation("User Profile Saved");
@ -269,12 +281,12 @@
private void Cancel()
{
NavigationManager.NavigateTo(NavigateUrl(""));
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
}
private void ProfileChanged(ChangeEventArgs e, string SettingName)
{
string value = (string)e.Value;
var value = (string)e.Value;
settings = SettingService.SetSetting(settings, SettingName, value);
}
@ -291,6 +303,7 @@
{
await NotificationService.DeleteNotificationAsync(Notification.NotificationId);
}
await logger.LogInformation("Notification Deleted {Notification}", Notification);
await LoadNotificationsAsync();
StateHasChanged();
@ -305,6 +318,7 @@
private async void FilterChanged(ChangeEventArgs e)
{
filter = (string)e.Value;
await LoadNotificationsAsync();
StateHasChanged();
}

View File

@ -1,7 +1,7 @@
@namespace Oqtane.Modules.Admin.UserProfile
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IUserRoleService UserRoleService
@inject IUserService UserService
@inject INotificationService NotificationService
@if (PageState.User != null)
@ -11,26 +11,35 @@
<td>
<label class="control-label">@title: </label>
</td>
@if (title == "From")
{
<td>
<select class="form-control" readonly @bind="userid">
<option value="-1">&lt;System&gt;</option>
@if (userroles != null)
{
foreach (UserRole userrole in userroles)
{
<option value="@userrole.UserId">@userrole.User.DisplayName</option>
}
}
</select>
<input class="form-control" @bind="@username" readonly />
</td>
}
@if (title == "To")
{
<td>
<input class="form-control" @bind="@username" />
</td>
}
</tr>
<tr>
<td>
<label class="control-label">Subject: </label>
</td>
@if (title == "From")
{
<td>
<input class="form-control" @bind="@subject" readonly />
</td>
}
@if (title == "To")
{
<td>
<input class="form-control" @bind="@subject" />
</td>
}
</tr>
@if (title == "From")
{
@ -39,10 +48,23 @@
<label class="control-label">Date: </label>
</td>
<td>
<input class="form-control" @bind="@createdon" />
<input class="form-control" @bind="@createdon" readonly />
</td>
</tr>
}
@if (title == "From")
{
<tr>
<td>
<label class="control-label">Message: </label>
</td>
<td>
<textarea class="form-control" @bind="@body" rows="5" readonly />
</td>
</tr>
}
@if (title == "To")
{
<tr>
<td>
<label class="control-label">Message: </label>
@ -51,55 +73,58 @@
<textarea class="form-control" @bind="@body" rows="5" />
</td>
</tr>
</table>
@if (reply != "")
{
<button type="button" class="btn btn-primary" @onclick="Send">Send</button>
}
</table>
@if (reply != string.Empty)
{
<button type="button" class="btn btn-primary" @onclick="Send">Send</button> }
else
{
if (title == "From")
{
<button type="button" class="btn btn-primary" @onclick="Reply">Reply</button>
}
<button type="button" class="btn btn-primary" @onclick="Reply">Reply</button>}
}
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<p>@reply</p>
}
@if (title == "To")
{
<div class="control-group">
<label class="control-label">Original Message </label>
<textarea class="form-control" @bind="@reply" rows="5" readonly />
</div>
}
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } }
public override string Title { get { return "View Notification"; } }
private int notificationid;
private string title = string.Empty;
private string username = "";
private string subject = string.Empty;
private string createdon = string.Empty;
private string body = string.Empty;
private string reply = string.Empty;
int notificationid;
string title = "";
List<UserRole> userroles;
string userid = "-1";
string subject = "";
string createdon = "";
string body = "";
string reply = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
public override string Title => "View Notification";
protected override async Task OnInitializedAsync()
{
try
{
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
userroles = userroles.Where(item => item.Role.Name == Constants.RegisteredRole || item.Role.Name == Constants.HostRole)
.OrderBy(item => item.User.DisplayName).ToList();
notificationid = Int32.Parse(PageState.QueryString["id"]);
Notification notification = await NotificationService.GetNotificationAsync(notificationid);
if (notification != null)
{
int userid = -1;
if (notification.ToUserId == PageState.User.UserId)
{
title = "From";
if (notification.FromUserId != null)
{
userid = notification.FromUserId.ToString();
userid = notification.FromUserId.Value;
}
}
else
@ -107,9 +132,21 @@
title = "To";
if (notification.ToUserId != null)
{
userid = notification.ToUserId.ToString();
userid = notification.ToUserId.Value;
}
}
if (userid != -1)
{
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
if (user != null)
{
username = user.Username;
}
}
if (username == "")
{
username = "System";
}
subject = notification.Subject;
createdon = notification.CreatedOn.ToString();
body = notification.Body;
@ -125,37 +162,51 @@
private void Reply()
{
title = "To";
if (!subject.Contains("RE:"))
{
subject = "RE: " + subject;
}
reply = body;
body = "\n\n____________________________________________\nSent: " + createdon + "\nSubject: " + subject + "\n\n" + body;
StateHasChanged();
}
private async Task Send()
{
Notification notification = new Notification();
var notification = new Notification();
try
{
var user = await UserService.GetUserAsync(username, PageState.Site.SiteId);
if (user != null)
{
notification.SiteId = PageState.Site.SiteId;
notification.FromUserId = PageState.User.UserId;
notification.ToUserId = int.Parse(userid);
notification.ToEmail = "";
notification.FromDisplayName = PageState.User.DisplayName;
notification.FromEmail = PageState.User.Email;
notification.ToUserId = user.UserId;
notification.ToDisplayName = user.DisplayName;
notification.ToEmail = user.Email;
notification.Subject = subject;
notification.Body = body;
notification.ParentId = notificationid;
notification.CreatedOn = DateTime.UtcNow;
notification.IsDelivered = false;
notification.DeliveredOn = null;
try
{
notification.SendOn = DateTime.UtcNow;
notification = await NotificationService.AddNotificationAsync(notification);
await logger.LogInformation("Notification Created {Notification}", notification);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage("User Does Not Exist. Please Verify That The Username Provided Is Correct.", MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Adding Notification {Notification} {Error}", notification, ex.Message);
AddModuleMessage("Error Adding Notification", MessageType.Error);
}
}
}

View File

@ -5,8 +5,10 @@
@inject IProfileService ProfileService
@inject ISettingService SettingService
@if (profiles != null)
{
<TabStrip>
<TabPanel Name="Identity">
@if (profiles != null)
{
<table class="table table-borderless">
<tr>
<td>
@ -48,7 +50,13 @@
<input class="form-control" @bind="@displayname" />
</td>
</tr>
</table>
}
</TabPanel>
<TabPanel Name="Profile">
@if (profiles != null)
{
<table class="table table-borderless">
@foreach (Profile profile in profiles)
{
var p = profile;
@ -71,21 +79,24 @@
</tr>
}
</table>
<button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
}
}
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private string username = string.Empty;
private string password = string.Empty;
private string confirm = string.Empty;
private string email = string.Empty;
private string displayname = string.Empty;
private List<Profile> profiles;
private Dictionary<string, string> settings;
private string category = string.Empty;
string username = "";
string password = "";
string confirm = "";
string email = "";
string displayname = "";
List<Profile> profiles;
Dictionary<string, string> settings;
string category = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
@ -105,11 +116,11 @@
{
try
{
if (username != "" && password != "" && confirm != "" && email != "")
if (username != string.Empty && password != string.Empty && confirm != string.Empty && email != string.Empty)
{
if (password == confirm)
{
User user = new User();
var user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = username;
user.Password = password;
@ -150,7 +161,7 @@
private void ProfileChanged(ChangeEventArgs e, string SettingName)
{
string value = (string)e.Value;
var value = (string)e.Value;
settings = SettingService.SetSetting(settings, SettingName, value);
}

View File

@ -5,16 +5,18 @@
@inject IProfileService ProfileService
@inject ISettingService SettingService
@if (profiles != null)
@if (PageState.User != null && photofileid != -1)
{
@if (photofileid != -1)
{
<img src="@(ContentUrl(photofileid))" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
}
else
{
}
else
{
<br />
}
}
<TabStrip>
<TabPanel Name="Identity">
@if (profiles != null)
{
<table class="table table-borderless">
<tr>
<td>
@ -61,10 +63,27 @@
<label class="control-label">Photo: </label>
</td>
<td>
<FileManager FileId="@photofileid.ToString()" @ref="filemanager" />
<FileManager FileId="@photofileid" @ref="filemanager" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Is Deleted? </label>
</td>
<td>
<select class="form-control" @bind="@isdeleted">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
}
</TabPanel>
<TabPanel Name="Profile">
@if (profiles != null)
{
<table class="table table-borderless">
@foreach (Profile profile in profiles)
{
var p = profile;
@ -86,46 +105,37 @@
</td>
</tr>
}
<tr>
<td>
<label class="control-label">Is Deleted? </label>
</td>
<td>
<select class="form-control" @bind="@isdeleted">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
<button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
}
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br /><br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private int userid;
private string username = string.Empty;
private string password = string.Empty;
private string confirm = string.Empty;
private string email = string.Empty;
private string displayname = string.Empty;
private FileManager filemanager;
private int photofileid = -1;
private List<Profile> profiles;
private Dictionary<string, string> settings;
private string category = string.Empty;
private string createdby;
private DateTime createdon;
private string modifiedby;
private DateTime modifiedon;
private string deletedby;
private DateTime? deletedon;
private string isdeleted;
int userid;
string username = "";
string password = "";
string confirm = "";
string email = "";
string displayname = "";
FileManager filemanager;
int photofileid = -1;
List<Profile> profiles;
Dictionary<string, string> settings;
string category = "";
string createdby;
DateTime createdon;
string modifiedby;
DateTime modifiedon;
string deletedby;
DateTime? deletedon;
string isdeleted;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
@ -134,16 +144,18 @@
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
userid = Int32.Parse(PageState.QueryString["id"]);
User user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
if (user != null)
{
username = user.Username;
email = user.Email;
displayname = user.DisplayName;
if (user.PhotoFileId != null)
{
photofileid = user.PhotoFileId.Value;
}
settings = await SettingService.GetUserSettingsAsync(user.UserId);
createdby = user.CreatedBy;
createdon = user.CreatedOn;
@ -162,19 +174,17 @@
}
private string GetProfileValue(string SettingName, string DefaultValue)
{
return SettingService.GetSetting(settings, SettingName, DefaultValue);
}
=> SettingService.GetSetting(settings, SettingName, DefaultValue);
private async Task SaveUser()
{
try
{
if (username != "" && password != "" && confirm != "" && email != "")
if (username != string.Empty && email != string.Empty)
{
if (password == confirm)
{
User user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
user.SiteId = PageState.Site.SiteId;
user.Username = username;
user.Password = password;
@ -182,10 +192,12 @@
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
user.PhotoFileId = null;
photofileid = filemanager.GetFileId();
if (photofileid != -1)
{
user.PhotoFileId = photofileid;
}
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
user = await UserService.UpdateUserAsync(user);
@ -213,7 +225,7 @@
private void ProfileChanged(ChangeEventArgs e, string SettingName)
{
string value = (string)e.Value;
var value = (string)e.Value;
settings = SettingService.SetSetting(settings, SettingName, value);
}

View File

@ -2,47 +2,86 @@
@inherits ModuleBase
@inject IUserRoleService UserRoleService
@inject IUserService UserService
@inject ISettingService SettingService
@if (userroles == null)
{
<p><em>Loading...</em></p>
<p>
<em>Loading...</em>
</p>
}
else
{
<ActionLink Action="Add" Text="Add User" />
<ActionLink Action="Add" Text="Add User"/>
<div class="d-flex p-1">
<input class="form-control mr-4" @bind="@_search"/><button class="btn btn-outline-primary ml-1" @onclick="OnSearch">Search</button>
</div>
<Pager Items="@userroles">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>Name</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" /></td>
<td><ActionDialog Header="Delete User" Message="@("Are You Sure You Wish To Delete " + context.User.DisplayName + "?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" /></td>
<td><ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" /></td>
<td>
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())"/>
</td>
<td>
<ActionDialog Header="Delete User" Message="@("Are You Sure You Wish To Delete " + context.User.DisplayName + "?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))"/>
</td>
<td>
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())"/>
</td>
<td>@context.User.DisplayName</td>
</Row>
</Pager>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private List<UserRole> allroles;
private List<UserRole> userroles;
private string _search;
List<UserRole> userroles;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
userroles = userroles.Where(item => item.Role.Name == Constants.RegisteredRole).ToList();
allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
await LoadSettingsAsync();
userroles = Search(_search);
}
private List<UserRole> Search(string search)
{
if (string.IsNullOrEmpty(_search))
{
return allroles.Where(item => item.Role.Name == Constants.RegisteredRole).ToList();
}
return allroles
.Where(item => item.Role.Name == Constants.RegisteredRole &&
(
item.User.Username.Contains(search, StringComparison.OrdinalIgnoreCase) ||
item.User.Email.Contains(search, StringComparison.OrdinalIgnoreCase) ||
item.User.DisplayName.Contains(search, StringComparison.OrdinalIgnoreCase)
)
)
.ToList();
}
private async Task OnSearch()
{
userroles = Search(_search);
await UpdateSettingsAsync();
}
private async Task DeleteUser(UserRole UserRole)
{
try
{
User user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId);
var user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId);
if (user != null)
{
await UserService.DeleteUserAsync(user.UserId);
@ -56,4 +95,20 @@ else
AddModuleMessage(ex.Message, MessageType.Error);
}
}
private string settingSearch = "AU-search";
private async Task LoadSettingsAsync()
{
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
_search = SettingService.GetSetting(settings, settingSearch, "");
}
private async Task UpdateSettingsAsync()
{
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
SettingService.SetSetting(settings, settingSearch, _search);
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
}
}

View File

@ -1,6 +1,7 @@
@namespace Oqtane.Modules.Admin.Users
@inherits ModuleBase
@inject IRoleService RoleService
@inject IUserService UserService
@inject IUserRoleService UserRoleService
@if (userroles == null)
@ -12,10 +13,18 @@ else
<table class="table table-borderless">
<tr>
<td>
<label class="control-label">Role: </label>
<Label For="user" HelpText="The user you are assigning roles to">User: </Label>
</td>
<td>
<select class="form-control" @bind="@roleid">
<input id="user" class="form-control" @bind="@name" disabled />
</td>
</tr>
<tr>
<td>
<Label For="role" HelpText="Select a role">Role: </Label>
</td>
<td>
<select id="role" class="form-control" @bind="@roleid">
<option value="-1">&lt;Select Role&gt;</option>
@foreach (Role role in roles)
{
@ -26,18 +35,18 @@ else
</tr>
<tr>
<td>
<label class="control-label">Effective Date: </label>
<Label For="effectiveDate" HelpText="The date that this role assignment is active">Effective Date: </Label>
</td>
<td>
<input class="form-control" @bind="@effectivedate" />
<input id="effectiveDate" class="form-control" @bind="@effectivedate" />
</td>
</tr>
<tr>
<td>
<label class="control-label">Expiry Date: </label>
<Label For="expiryDate" HelpText="The date that this role assignment expires">Expiry Date: </Label>
</td>
<td>
<input class="form-control" @bind="@expirydate" />
<input id="expiryDate" class="form-control" @bind="@expirydate" />
</td>
</tr>
</table>
@ -48,13 +57,13 @@ else
<p align="center">
<Pager Items="@userroles">
<Header>
<th>Role</th>
<th>Roles</th>
<th>&nbsp;</th>
</Header>
<Row>
<td>@context.Role.Name</td>
<td>
@if (!context.Role.IsSystem)
@if (context.Role.Name != Constants.RegisteredRole)
{
<button type="button" class="btn btn-danger" @onclick=@(async () => await DeleteUserRole(context.UserRoleId))>Delete</button>
}
@ -65,20 +74,23 @@ else
}
@code {
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } }
private int userid;
private string name = string.Empty;
private List<Role> roles;
private int roleid = -1;
private string effectivedate = string.Empty;
private string expirydate = string.Empty;
private List<UserRole> userroles;
int userid;
List<Role> roles;
int roleid = -1;
string effectivedate = "";
string expirydate = "";
List<UserRole> userroles;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
try
{
userid = Int32.Parse(PageState.QueryString["id"]);
User user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
name = user.DisplayName;
roles = await RoleService.GetRolesAsync(PageState.Site.SiteId);
await GetUserRoles();
}
@ -109,7 +121,7 @@ else
{
if (roleid != -1)
{
UserRole userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault();
var userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault();
if (userrole != null)
{
if (string.IsNullOrEmpty(effectivedate))
@ -120,6 +132,7 @@ else
{
userrole.EffectiveDate = DateTime.Parse(effectivedate);
}
if (string.IsNullOrEmpty(expirydate))
{
userrole.ExpiryDate = null;
@ -135,6 +148,7 @@ else
userrole = new UserRole();
userrole.UserId = userid;
userrole.RoleId = roleid;
if (string.IsNullOrEmpty(effectivedate))
{
userrole.EffectiveDate = null;
@ -143,6 +157,7 @@ else
{
userrole.EffectiveDate = DateTime.Parse(effectivedate);
}
if (string.IsNullOrEmpty(expirydate))
{
userrole.ExpiryDate = null;
@ -151,8 +166,10 @@ else
{
userrole.ExpiryDate = DateTime.Parse(expirydate);
}
await UserRoleService.AddUserRoleAsync(userrole);
}
await GetUserRoles();
await logger.LogInformation("User Assigned To Role {UserRole}", userrole);
AddModuleMessage("User Assigned To Role", MessageType.Success);

View File

@ -1,6 +1,6 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@if (_visible)
{
<div class="app-admin-modal">
@ -17,7 +17,7 @@
<div class="modal-footer">
@if (!string.IsNullOrEmpty(Action))
{
<button type="button" class="@Class" @onclick="Confirm">@Action</button>
<button type="button" class="@Class" @onclick="Confirm">@((MarkupString)_iconSpan) @Action</button>
}
<button type="button" class="btn btn-secondary" @onclick="DisplayModal">Cancel</button>
</div>
@ -30,15 +30,20 @@
{
if (Disabled)
{
<button class="@Class" disabled @onclick="DisplayModal">@Text</button>
<button class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
}
else
{
<button class="@Class" @onclick="DisplayModal">@Text</button>
<button class="@Class" @onclick="DisplayModal">@((MarkupString)_iconSpan) @Text</button>
}
}
@code {
private bool _visible = false;
private bool _editmode = true;
private bool _authorized = false;
private string _iconSpan = string.Empty;
[Parameter]
public string Header { get; set; } // required
@ -66,9 +71,8 @@
[Parameter]
public Action OnClick { get; set; } // required if an Action is specified - executes a method in the calling component
bool _visible = false;
bool _editmode = true;
bool _authorized = false;
[Parameter]
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
protected override void OnParametersSet()
{
@ -84,6 +88,12 @@
{
_editmode = bool.Parse(EditMode);
}
if (!string.IsNullOrEmpty(IconName))
{
_iconSpan = $"<span class=\"oi oi-{IconName}\"></span>&nbsp;";
}
_authorized = IsAuthorized();
}
@ -99,8 +109,8 @@
Type moduleType = Type.GetType(typename);
if (moduleType != null)
{
var moduleobject = Activator.CreateInstance(moduleType);
security = (SecurityAccessLevel)moduleType.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
var moduleobject = Activator.CreateInstance(moduleType) as IModuleControl;
security = moduleobject.SecurityAccessLevel;
}
else
{

View File

@ -1,20 +1,30 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inject IUserService UserService
@if (_authorized)
{
if (Disabled)
{
<NavLink class="@_classname" href="@_url" style="@_style" disabled>@_text</NavLink>
<button class="@_classname" style="@_style" disabled>@((MarkupString)_iconSpan) @_text</button>
}
else
{
<NavLink class="@_classname" href="@_url" style="@_style">@_text</NavLink>
<NavLink class="@_classname" href="@_url" style="@_style">@((MarkupString)_iconSpan) @_text</NavLink>
}
}
@code {
private string _text = string.Empty;
private string _url = string.Empty;
private string _parameters = string.Empty;
private string _classname = "btn btn-primary";
private string _style = string.Empty;
private bool _editmode = true;
private bool _authorized = false;
private string _iconSpan = string.Empty;
[Parameter]
public string Action { get; set; } // required
@ -39,13 +49,11 @@
[Parameter]
public string EditMode { get; set; } // optional - specifies if a user must be in edit mode to see the action - default is true
string _text = "";
string _url = "";
string _parameters = "";
string _classname = "btn btn-primary";
string _style = "";
bool _editmode = true;
bool _authorized = 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
protected override void OnParametersSet()
{
@ -55,6 +63,11 @@
_text = Text;
}
if (IconOnly && !string.IsNullOrEmpty(IconName))
{
_text = string.Empty;
}
if (!string.IsNullOrEmpty(Parameters))
{
_parameters = Parameters;
@ -75,24 +88,30 @@
_editmode = bool.Parse(EditMode);
}
if (!string.IsNullOrEmpty(IconName))
{
_iconSpan = $"<span class=\"oi oi-{IconName}\"></span>{(IconOnly?"":"&nbsp")}";
}
_url = EditUrl(Action, _parameters);
_authorized = IsAuthorized();
}
private bool IsAuthorized()
{
bool authorized = false;
var authorized = false;
if (PageState.EditMode || !_editmode)
{
SecurityAccessLevel security = SecurityAccessLevel.Host;
var security = SecurityAccessLevel.Host;
if (Security == null)
{
string typename = ModuleState.ModuleType.Replace(Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0) + ",", Action + ",");
Type moduleType = Type.GetType(typename);
var typename = ModuleState.ModuleType.Replace(Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0) + ",", Action + ",");
var moduleType = Type.GetType(typename);
if (moduleType != null)
{
var moduleobject = Activator.CreateInstance(moduleType);
security = (SecurityAccessLevel)moduleType.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
var moduleobject = Activator.CreateInstance(moduleType) as IModuleControl;
security = moduleobject.SecurityAccessLevel;
}
else
{
@ -104,16 +123,17 @@
{
security = Security.Value;
}
switch (security)
{
case SecurityAccessLevel.Anonymous:
authorized = true;
break;
case SecurityAccessLevel.View:
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, ModuleState.Permissions);
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, ModuleState.Permissions);
break;
case SecurityAccessLevel.Edit:
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions);
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions);
break;
case SecurityAccessLevel.Admin:
authorized = UserSecurity.IsAuthorized(PageState.User, Constants.AdminRole);
@ -123,6 +143,7 @@
break;
}
}
return authorized;
}
}

View File

@ -1,12 +1,16 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@if (_text != "")
@if (_text != string.Empty)
{
@((MarkupString)_text)
}
@code {
private string _text = string.Empty;
[Parameter]
public string CreatedBy { get; set; }
@ -31,50 +35,57 @@
[Parameter]
public string Style { get; set; }
string _text = "";
protected override void OnParametersSet()
{
_text = "";
_text = string.Empty;
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,14 +1,17 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inject IFolderService FolderService
@inject IFileService FileService
@inject IJSRuntime JsRuntime
@if (_folders != null)
{
<div class="container-fluid px-0">
<div id="@Id" class="container-fluid px-0">
<div class="row">
<div class="col">
@if (ShowFolders || FolderId <= 0)
{
<div>
<select class="form-control" @onchange="(e => FolderChanged(e))">
@if (string.IsNullOrEmpty(Folder))
@ -17,7 +20,7 @@
}
@foreach (Folder folder in _folders)
{
if (folder.FolderId == _folderid)
if (folder.FolderId == FolderId)
{
<option value="@(folder.FolderId)" selected>@(new string('-', folder.Level * 2))@(folder.Name)</option>
}
@ -28,14 +31,15 @@
}
</select>
</div>
@if (_showfiles)
}
@if (ShowFiles)
{
<div>
<select class="form-control" @onchange="(e => FileChanged(e))">
<option value="-1">&lt;Select File&gt;</option>
@foreach (File file in _files)
{
if (file.FileId == _fileid)
if (file.FileId == FileId)
{
<option value="@(file.FileId)" selected>@(file.Name)</option>
}
@ -47,16 +51,16 @@
</select>
</div>
}
@if (_haseditpermission)
@if (ShowUpload && _haseditpermission)
{
<div>
@if (_uploadmultiple)
@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">
@ -67,13 +71,13 @@
}
</span>
</div>
@((MarkupString)_message)
}
@((MarkupString) _message)
</div>
@if (_image != "")
@if (_image != string.Empty)
{
<div class="col-auto">
@((MarkupString)_image)
@((MarkupString) _image)
</div>
}
</div>
@ -81,90 +85,89 @@
}
@code {
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;
private string _filter = "*";
private bool _haseditpermission = false;
private string _message = string.Empty;
private string _image = string.Empty;
private string _guid;
[Parameter]
public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility
[Parameter]
public string Folder { get; set; } // optional - for setting a specific folder by default
[Parameter]
public string FolderId { get; set; } // optional - for setting a specific folderid by default
public int FolderId { get; set; } = -1; // optional - for setting a specific folderid by default
[Parameter]
public string ShowFiles { get; set; } // optional - for indicating whether a list of files should be displayed - default is true
public bool ShowFiles { get; set; } = true; // optional - for indicating whether a list of files should be displayed - default is true
[Parameter]
public string FileId { get; set; } // optional - for setting a specific file by default
public bool ShowUpload { get; set; } = true; // optional - for indicating whether a Upload controls should be displayed - default is true
[Parameter]
public bool ShowFolders { get; set; } = true; // optional - for indicating whether a list of folders should be displayed - default is true
[Parameter]
public int FileId { get; set; } = -1; // optional - for setting a specific file by default
[Parameter]
public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"
[Parameter]
public string UploadMultiple { get; set; } // optional - enable multiple file uploads - default false
string _id;
List<Folder> _folders;
int _folderid = -1;
List<File> _files = new List<File>();
int _fileid = -1;
bool _showfiles = true;
string _fileinputid = "";
string _progressinfoid = "";
string _progressbarid = "";
string _filter = "*";
bool _uploadmultiple = false;
bool _haseditpermission = false;
string _message = "";
string _image = "";
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
protected override async Task OnInitializedAsync()
{
if (!string.IsNullOrEmpty(Id))
{
_id = Id;
}
if (!string.IsNullOrEmpty(Folder))
{
_folders = new List<Folder> {new Folder {FolderId = -1, Name = Folder}};
_folderid = -1;
FolderId = -1;
}
else
{
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
if (!string.IsNullOrEmpty(FolderId))
{
_folderid = int.Parse(FolderId);
}
}
if (!string.IsNullOrEmpty(FileId))
if (FileId != -1)
{
_fileid = int.Parse(FileId);
await SetImage();
if (_fileid != -1)
{
File file = await FileService.GetFileAsync(int.Parse(FileId));
File file = await FileService.GetFileAsync(FileId);
if (file != null)
{
_folderid = file.FolderId;
FolderId = file.FolderId;
}
}
}
if (!string.IsNullOrEmpty(ShowFiles))
else
{
_showfiles = bool.Parse(ShowFiles);
FileId = -1; // file does not exist
}
}
await SetImage();
if (!string.IsNullOrEmpty(Filter))
{
_filter = "." + Filter.Replace(",",",.");
_filter = "." + Filter.Replace(",", ",.");
}
await GetFiles();
// create unique id for component
_id = Guid.NewGuid().ToString("N");
_fileinputid = _id + "FileInput";
_progressinfoid = _id + "ProgressInfo";
_progressbarid = _id + "ProgressBar";
if (!string.IsNullOrEmpty(UploadMultiple))
{
_uploadmultiple = bool.Parse(UploadMultiple);
}
_guid = Guid.NewGuid().ToString("N");
_fileinputid = _guid + "FileInput";
_progressinfoid = _guid + "ProgressInfo";
_progressbarid = _guid + "ProgressBar";
}
private async Task GetFiles()
@ -177,11 +180,11 @@
}
else
{
Folder folder = _folders.FirstOrDefault(item => item.FolderId == _folderid);
Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId);
if (folder != null)
{
_haseditpermission = UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, folder.Permissions);
_files = await FileService.GetFilesAsync(_folderid);
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.Permissions);
_files = await FileService.GetFilesAsync(FolderId);
}
else
{
@ -205,13 +208,13 @@
private async Task FolderChanged(ChangeEventArgs e)
{
_message = "";
_message = string.Empty;
try
{
_folderid = int.Parse((string)e.Value);
FolderId = int.Parse((string) e.Value);
await GetFiles();
_fileid = -1;
_image = "";
FileId = -1;
_image = string.Empty;
StateHasChanged();
}
catch (Exception ex)
@ -223,28 +226,29 @@
private async Task FileChanged(ChangeEventArgs e)
{
_message = "";
_fileid = int.Parse((string)e.Value);
_message = string.Empty;
FileId = int.Parse((string) e.Value);
await SetImage();
StateHasChanged();
}
private async Task SetImage()
{
_image = "";
if (_fileid != -1)
_image = string.Empty;
if (FileId != -1)
{
File file = await FileService.GetFileAsync(_fileid);
if (file.ImageHeight != 0 && file.ImageWidth != 0)
File file = await FileService.GetFileAsync(FileId);
if (file != null && file.ImageHeight != 0 && file.ImageWidth != 0)
{
int maxwidth = 200;
int maxheight = 200;
var maxwidth = 200;
var maxheight = 200;
double ratioX = (double)maxwidth / (double)file.ImageWidth;
double ratioY = (double)maxheight / (double)file.ImageHeight;
double ratio = ratioX < ratioY ? ratioX : ratioY;
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 +
_image = "<img src=\"" + ContentUrl(FileId) + "\" alt=\"" + file.Name +
"\" width=\"" + Convert.ToInt32(file.ImageWidth * ratio).ToString() +
"\" height=\"" + Convert.ToInt32(file.ImageHeight * ratio).ToString() + "\" />";
}
@ -253,8 +257,8 @@
private async Task UploadFile()
{
var interop = new Interop(JsRuntime);
string[] upload = await interop.GetFiles(_fileinputid);
var interop = new Interop(JSRuntime);
var upload = await interop.GetFiles(_fileinputid);
if (upload.Length > 0)
{
try
@ -262,23 +266,25 @@
string result;
if (!string.IsNullOrEmpty(Folder))
{
result = await FileService.UploadFilesAsync(Folder, upload, _id);
result = await FileService.UploadFilesAsync(Folder, upload, _guid);
}
else
{
result = await FileService.UploadFilesAsync(_folderid, upload, _id);
result = await FileService.UploadFilesAsync(FolderId, upload, _guid);
}
if (result == "")
if (result == string.Empty)
{
await logger.LogInformation("File Upload Succeeded {Files}", upload);
_message = "<br /><div class=\"alert alert-success\" role=\"alert\">File Upload Succeeded</div>";
await GetFiles();
if (upload.Length == 1)
{
File file = _files.Where(item => item.Name == upload[0]).FirstOrDefault();
var file = _files.Where(item => item.Name == upload[0]).FirstOrDefault();
if (file != null)
{
_fileid = file.FileId;
FileId = file.FileId;
await SetImage();
}
}
@ -304,27 +310,25 @@
private async Task DeleteFile()
{
_message = "";
_message = string.Empty;
try
{
await FileService.DeleteFileAsync(_fileid);
await logger.LogInformation("File Deleted {File}", _fileid);
await FileService.DeleteFileAsync(FileId);
await logger.LogInformation("File Deleted {File}", FileId);
_message = "<br /><div class=\"alert alert-success\" role=\"alert\">File Deleted</div>";
await GetFiles();
_fileid = -1;
FileId = -1;
await SetImage();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting File {File} {Error}", _fileid, ex.Message);
await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message);
_message = "<br /><div class=\"alert alert-danger\" role=\"alert\">Error Deleting File</div>";
}
}
public int GetFileId()
{
return _fileid;
}
public int GetFileId() => FileId;
}

View File

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

View File

@ -1,5 +1,6 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@if (!string.IsNullOrEmpty(_message))
{
@ -8,15 +9,15 @@
}
@code {
private string _message = string.Empty;
private string _classname = "alert alert-danger";
[Parameter]
public string Message { get; set; }
[Parameter]
public MessageType Type { get; set; }
string _message = "";
string _classname = "alert alert-danger";
protected override void OnParametersSet()
{
if (!string.IsNullOrEmpty(Message))
@ -35,7 +36,7 @@
private string GetMessageType(MessageType type)
{
string classname = "";
var classname = string.Empty;
switch (type)
{
case MessageType.Success:
@ -51,6 +52,7 @@
classname = "alert alert-danger";
break;
}
return classname;
}
}

View File

@ -1,6 +1,8 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@typeparam TAbleItem
@attribute [OqtaneIgnore]
@typeparam TableItem
<p>
@if(Format == "Table")
@ -64,12 +66,12 @@
</p>
@code {
int _pages = 0;
int _page = 1;
int _maxItems;
int _maxPages;
int _startPage;
int _endPage;
private int _pages = 0;
private int _page = 1;
private int _maxItems;
private int _maxPages;
private int _startPage;
private int _endPage;
[Parameter]
public string Format { get; set; }
@ -78,13 +80,13 @@
public RenderFragment Header { get; set; }
[Parameter]
public RenderFragment<TAbleItem> Row { get; set; }
public RenderFragment<TableItem> Row { get; set; }
[Parameter]
public RenderFragment<TAbleItem> Detail { get; set; }
public RenderFragment<TableItem> Detail { get; set; }
[Parameter]
public IEnumerable<TAbleItem> Items { get; set; }
public IEnumerable<TableItem> Items { get; set; }
[Parameter]
public string PageSize { get; set; }
@ -95,7 +97,7 @@
[Parameter]
public string Class { get; set; }
IEnumerable<TAbleItem> ItemList { get; set; }
private IEnumerable<TableItem> ItemList { get; set; }
protected override void OnParametersSet()
{
@ -103,6 +105,7 @@
{
Format = "Table";
}
if (string.IsNullOrEmpty(Class))
{
if (Format == "Table")
@ -114,6 +117,7 @@
Class = "container";
}
}
if (string.IsNullOrEmpty(PageSize))
{
_maxItems = 10;
@ -122,6 +126,7 @@
{
_maxItems = int.Parse(PageSize);
}
if (string.IsNullOrEmpty(DisplayPages))
{
_maxPages = 5;
@ -144,6 +149,7 @@
{
ItemList = Items.Skip((currentPage - 1) * _maxItems).Take(_maxItems);
_page = currentPage;
StateHasChanged();
}
@ -168,6 +174,7 @@
{
_endPage = _pages;
}
StateHasChanged();
}
else if (direction == "back")
@ -201,6 +208,7 @@
_page -= 1;
}
}
UpdateList(_page);
}
}

View File

@ -1,18 +1,19 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@inject IRoleService RoleService
@inject IUserService UserService
@if (_permissions != null)
{
<br />
<table class="table">
<table class="table" style="width: 50%; min-width: 250px;">
<tbody>
<tr>
<th>Role</th>
<th scope="col">Role</th>
@foreach (PermissionString permission in _permissions)
{
<th style="text-align: center;">@permission.PermissionName @EntityName</th>
<th style="text-align: center; width: 1px;">@permission.PermissionName</th>
}
</tr>
@foreach (Role role in _roles)
@ -32,13 +33,13 @@
</table>
@if (_users.Count != 0)
{
<table class="table">
<table class="table" style="width: 50%; min-width: 250px;">
<thead>
<tr>
<th>User</th>
<th scope="col">User</th>
@foreach (PermissionString permission in _permissions)
{
<th style="text-align: center;">@permission.PermissionName @EntityName</th>
<th style="text-align: center; width: 1px;">@permission.PermissionName</th>
}
</tr>
</thead>
@ -47,11 +48,11 @@
{
string userid = "[" + user.UserId.ToString() + "]";
<tr>
<td>@user.DisplayName</td>
<td >@user.DisplayName</td>
@foreach (PermissionString permission in _permissions)
{
var p = permission;
<td style="text-align: center;">
<td style="text-align: center; width: 1px;">
<TriStateCheckBox Value=@GetPermissionValue(p.Permissions, userid) Disabled=false OnChange="@(e => PermissionChanged(e, p.PermissionName, userid))" />
</td>
}
@ -60,12 +61,13 @@
</tbody>
</table>
}
<table class="table">
<table class="table" style="width: 50%; min-width: 250px;">
<tbody>
<tr>
<td style="text-align: right;"><label for="Username" class="control-label">User: </label></td>
<td><input type="text" name="Username" class="form-control" placeholder="Enter Username" @bind="@_username" /></td>
<td style="text-align: left;"><button type="button" class="btn btn-primary" @onclick="AddUser">Add</button></td>
<td class="input-group">
<input type="text" name="Username" class="form-control" placeholder="Enter Username" @bind="@_username" />
<button type="button" class="btn btn-primary" @onclick="AddUser">Add</button>
</td>
</tr>
</tbody>
</table>
@ -74,6 +76,13 @@
}
@code {
private string _permissionnames = string.Empty;
private List<Role> _roles;
private List<PermissionString> _permissions;
private List<User> _users = new List<User>();
private string _username = string.Empty;
private string _message = string.Empty;
[Parameter]
public string EntityName { get; set; }
@ -83,46 +92,45 @@
[Parameter]
public string Permissions { get; set; }
string _permissionnames = "";
List<Role> _roles;
List<PermissionString> _permissions;
List<User> _users = new List<User>();
string _username = "";
string _message = "";
protected override async Task OnInitializedAsync()
{
if (string.IsNullOrEmpty(PermissionNames))
{
_permissionnames = "View,Edit";
_permissionnames = Shared.PermissionNames.View + "," + Shared.PermissionNames.Edit;
}
else
{
_permissionnames = PermissionNames;
}
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId);
_roles.Insert(0, new Role { Name = Constants.AllUsersRole });
if (!string.IsNullOrEmpty(Permissions))
{
_permissions = new List<PermissionString>();
foreach (string permissionname in _permissionnames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
_permissions.Add(new PermissionString { PermissionName = permissionname, Permissions = "" });
// initialize with admin role
_permissions.Add(new PermissionString { PermissionName = permissionname, Permissions = Constants.AdminRole });
}
if (!string.IsNullOrEmpty(Permissions))
{
// populate permissions
foreach (PermissionString permissionstring in UserSecurity.GetPermissionStrings(Permissions))
{
if (_permissions.Find(item => item.PermissionName == permissionstring.PermissionName) != null)
{
_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))
{
if (user.Contains("]"))
{
int userid = int.Parse(user.Substring(0, user.IndexOf("]")));
var userid = int.Parse(user.Substring(0, user.IndexOf("]")));
if (_users.Where(item => item.UserId == userid).FirstOrDefault() == null)
{
_users.Add(await UserService.GetUserAsync(userid, ModuleState.SiteId));
@ -154,16 +162,9 @@
}
private bool GetPermissionDisabled(string roleName)
{
if (roleName == Constants.AdminRole)
{
return true;
}
else
{
return false;
}
}
=> roleName == Constants.AdminRole
? true
: false;
private async Task AddUser()
{
@ -171,7 +172,7 @@
{
try
{
User user = await UserService.GetUserAsync(_username, ModuleState.SiteId);
var user = await UserService.GetUserAsync(_username, ModuleState.SiteId);
if (user != null)
{
_users.Add(user);
@ -182,16 +183,17 @@
_message = "Username Does Not Exist";
}
}
_username = "";
_username = string.Empty;
}
private void PermissionChanged(bool? value, string permissionName, string securityId)
{
bool? selected = value;
PermissionString permission = _permissions.Find(item => item.PermissionName == permissionName);
var selected = value;
var permission = _permissions.Find(item => item.PermissionName == permissionName);
if (permission != null)
{
List<string> ids = permission.Permissions.Split(';').ToList();
var ids = permission.Permissions.Split(';').ToList();
ids.Remove(securityId); // remove grant permission
ids.Remove("!" + securityId); // remove deny permission
@ -207,6 +209,7 @@
case null:
break; // permission not specified
}
_permissions[_permissions.FindIndex(item => item.PermissionName == permissionName)].Permissions = string.Join(";", ids.ToArray());
}
}

View File

@ -1,34 +1,95 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@inject IJSRuntime JsRuntime
@attribute [OqtaneIgnore]
@if (_filemanagervisible)
{
<div class="row" style="margin-bottom: 50px;">
<div class="col">
<TabStrip>
<TabPanel Name="Rich" Heading="Rich Text Editor">
@if (_filemanagervisible)
{
<FileManager @ref="_fileManager" Filter="@Constants.ImageFiles" />
@((MarkupString)_message)
<br />
}
<div class="row justify-content-center">
<button type="button" class="btn btn-success" @onclick="InsertImage">Insert Image</button>
}
<div class="row justify-content-center" style="margin-bottom: 20px;">
<button type="button" class="btn btn-secondary" @onclick="RefreshRichText">Synchronize Content</button>&nbsp;&nbsp;
<button type="button" class="btn btn-primary" @onclick="InsertImage">Insert Image</button>
@if (_filemanagervisible)
{
@((MarkupString)"&nbsp;&nbsp;")
<button type="button" class="btn btn-secondary" @onclick="CloseFileManager">Close</button>
}
</div>
<div class="row">
<div class ="col">
</div>
<div class="row">
<div class="col">
<div @ref="@_toolBar">
@if (ToolbarContent != null)
{
@ToolbarContent
}
else
{
<select class="ql-header">
<option selected=""></option>
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
<option value="4"></option>
<option value="5"></option>
</select>
<span class="ql-formats">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<button class="ql-strike"></button>
</span>
<span class="ql-formats">
<select class="ql-color"></select>
<select class="ql-background"></select>
</span>
<span class="ql-formats">
<button class="ql-list" value="ordered"></button>
<button class="ql-list" value="bullet"></button>
</span>
<span class="ql-formats">
<button class="ql-link"></button>
</span>
}
</div>
<div @ref="@_editorElement">
</div>
</div>
</div>
</TabPanel>
<TabPanel Name="Raw" Heading="Raw HTML Editor">
<div class="row justify-content-center" style="margin-bottom: 20px;">
<button type="button" class="btn btn-secondary" @onclick="RefreshRawHtml">Synchronize Content</button>
</div>
@if (ReadOnly)
{
<textarea class="form-control" placeholder="@Placeholder" @bind="@_content" rows="10" readonly></textarea>
}
else
{
<textarea class="form-control" placeholder="@Placeholder" @bind="@_content" rows="10"></textarea>
}
</TabPanel>
</TabStrip>
</div>
</div>
@code {
private ElementReference _editorElement;
private ElementReference _toolBar;
private bool _filemanagervisible = false;
private FileManager _fileManager;
private string _content = string.Empty;
private string _original = string.Empty;
private string _message = string.Empty;
[Parameter]
public RenderFragment ToolbarContent { get; set; }
public string Content { get; set; }
[Parameter]
public bool ReadOnly { get; set; } = false;
@ -36,80 +97,100 @@
[Parameter]
public string Placeholder { get; set; } = "Enter Your Content...";
// parameters only applicable to rich text editor
[Parameter]
public RenderFragment ToolbarContent { get; set; }
[Parameter]
public string Theme { get; set; } = "snow";
[Parameter]
public string DebugLevel { get; set; } = "info";
private ElementReference _editorElement;
private ElementReference _toolBar;
bool _filemanagervisible = false;
FileManager _fileManager;
string _message = "";
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
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await RichTextEditorInterop.CreateEditor(
JsRuntime,
await base.OnAfterRenderAsync(firstRender);
var interop = new RichTextEditorInterop(JSRuntime);
await interop.CreateEditor(
_editorElement,
_toolBar,
ReadOnly,
Placeholder,
Theme,
DebugLevel);
await interop.LoadEditorContent(_editorElement, Content);
// preserve a copy of the rich text content ( Quill sanitizes content so we need to retrieve it from the editor )
_original = await interop.GetHtml(_editorElement);
}
}
public async Task<string> GetText()
public void CloseFileManager()
{
return await RichTextEditorInterop.GetText(
JsRuntime,
_editorElement);
_filemanagervisible = false;
_message = string.Empty;
StateHasChanged();
}
public async Task RefreshRichText()
{
var interop = new RichTextEditorInterop(JSRuntime);
await interop.LoadEditorContent(_editorElement, _content);
}
public async Task RefreshRawHtml()
{
var interop = new RichTextEditorInterop(JSRuntime);
_content = await interop.GetHtml(_editorElement);
StateHasChanged();
}
public async Task<string> GetHtml()
{
return await RichTextEditorInterop.GetHtml(
JsRuntime,
_editorElement);
}
// get rich text content
var interop = new RichTextEditorInterop(JSRuntime);
string content = await interop.GetHtml(_editorElement);
public async Task<string> GetContent()
if (_original != content)
{
return await RichTextEditorInterop.GetContent(
JsRuntime,
_editorElement);
// rich text content has changed - return it
return content;
}
public async Task LoadContent(string content)
else
{
await RichTextEditorInterop.LoadEditorContent(
JsRuntime,
_editorElement, content);
// return raw html content
return _content;
}
public async Task EnableEditor(bool mode)
{
await RichTextEditorInterop.EnableEditor(
JsRuntime,
_editorElement, mode);
}
public async Task InsertImage()
{
if (_filemanagervisible)
{
int fileid = _fileManager.GetFileId();
var fileid = _fileManager.GetFileId();
if (fileid != -1)
{
await RichTextEditorInterop.InsertImage(
JsRuntime,
_editorElement, ContentUrl(fileid));
var interop = new RichTextEditorInterop(JSRuntime);
await interop.InsertImage(_editorElement, ContentUrl(fileid));
_filemanagervisible = false;
_message = "";
_message = string.Empty;
}
else
{
@ -119,16 +200,27 @@
else
{
_filemanagervisible = true;
_message = "";
_message = string.Empty;
}
StateHasChanged();
}
public void CloseFileManager()
// other rich text editor methods which can be used by developers
public async Task<string> GetText()
{
_filemanagervisible = false;
_message = "";
StateHasChanged();
var interop = new RichTextEditorInterop(JSRuntime);
return await interop.GetText(_editorElement);
}
public async Task<string> GetContent()
{
var interop = new RichTextEditorInterop(JSRuntime);
return await interop.GetContent(_editorElement);
}
public async Task EnableEditor(bool mode)
{
var interop = new RichTextEditorInterop(JSRuntime);
await interop.EnableEditor(_editorElement, mode);
}
}

View File

@ -0,0 +1,123 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Threading.Tasks;
namespace Oqtane.Modules.Controls
{
public class RichTextEditorInterop
{
private readonly IJSRuntime _jsRuntime;
public RichTextEditorInterop(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
public async Task CreateEditor(
ElementReference quillElement,
ElementReference toolbar,
bool readOnly,
string placeholder,
string theme,
string debugLevel)
{
try
{
await _jsRuntime.InvokeAsync<object>(
"Oqtane.RichTextEditor.createQuill",
quillElement, toolbar, readOnly, placeholder, theme, debugLevel);
return;
}
catch
{
// handle exception
}
}
public ValueTask<string> GetText(ElementReference quillElement)
{
try
{
return _jsRuntime.InvokeAsync<string>(
"Oqtane.RichTextEditor.getQuillText",
quillElement);
}
catch
{
return new ValueTask<string>(Task.FromResult(string.Empty));
}
}
public ValueTask<string> GetHtml(ElementReference quillElement)
{
try
{
return _jsRuntime.InvokeAsync<string>(
"Oqtane.RichTextEditor.getQuillHTML",
quillElement);
}
catch
{
return new ValueTask<string>(Task.FromResult(string.Empty));
}
}
public ValueTask<string> GetContent(ElementReference quillElement)
{
try
{
return _jsRuntime.InvokeAsync<string>(
"Oqtane.RichTextEditor.getQuillContent",
quillElement);
}
catch
{
return new ValueTask<string>(Task.FromResult(string.Empty));
}
}
public Task LoadEditorContent(ElementReference quillElement, string content)
{
try
{
_jsRuntime.InvokeAsync<object>(
"Oqtane.RichTextEditor.loadQuillContent",
quillElement, content);
return Task.CompletedTask;
}
catch
{
return Task.CompletedTask;
}
}
public Task EnableEditor(ElementReference quillElement, bool mode)
{
try
{
_jsRuntime.InvokeAsync<object>(
"Oqtane.RichTextEditor.enableQuillEditor", quillElement, mode);
return Task.CompletedTask;
}
catch
{
return Task.CompletedTask;
}
}
public Task InsertImage(ElementReference quillElement, string imageUrl)
{
try
{
_jsRuntime.InvokeAsync<object>(
"Oqtane.RichTextEditor.insertQuillImage",
quillElement, imageUrl);
return Task.CompletedTask;
}
catch
{
return Task.CompletedTask;
}
}
}
}

View File

@ -0,0 +1,45 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
<div class="d-flex">
<div>
<a data-toggle="collapse" class="app-link-unstyled" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name" @onclick:preventDefault="true">
<h5>@_heading</h5>
</a>
</div>
<div class="ml-auto">
<a data-toggle="collapse" class="app-link-unstyled float-right" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name" @onclick:preventDefault="true">
<i class="oi oi-chevron-bottom"></i>&nbsp;
</a>
</div>
</div>
<div class="d-flex">
<hr class="app-rule" />
</div>
<div class="collapse" id="@Name">
@ChildContent
</div>
@code {
private string _heading = string.Empty;
private string _expanded = string.Empty;
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public string Name { get; set; } // required - the name of the section
[Parameter]
public string Heading { get; set; } // optional - will default to Name if not provided
[Parameter]
public string Expanded { get; set; } // optional - will default to false if not provided
protected override void OnInitialized()
{
_heading = (!string.IsNullOrEmpty(Heading)) ? Heading : Name;
_expanded = (!string.IsNullOrEmpty(Expanded)) ? Expanded : "false";
}
}

View File

@ -1,43 +0,0 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
<CascadingValue Value="this">
<div>
@foreach (TabPanel tabPanel in _tabPanels)
{
<button type="button"
class="btn @GetButtonClass(tabPanel)"
@onclick=@( () => ActivateTabPanel(tabPanel) )>
@tabPanel.Text
</button>
}
</div>
@ChildContent
</CascadingValue>
@code {
// Next line is needed so we are able to add <TabPanel> components inside
[Parameter]
public RenderFragment ChildContent { get; set; }
public TabPanel ActiveTabPanel { get; set; }
List<TabPanel> _tabPanels = new List<TabPanel>();
internal void AddTabPanel(TabPanel tabPanel)
{
_tabPanels.Add(tabPanel);
if (_tabPanels.Count == 1)
ActiveTabPanel = tabPanel;
StateHasChanged();
}
string GetButtonClass(TabPanel tabPanel)
{
return tabPanel == ActiveTabPanel ? "btn-primary" : "btn-secondary";
}
void ActivateTabPanel(TabPanel tabPanel)
{
ActiveTabPanel = tabPanel;
}
}

View File

@ -1,27 +1,36 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
@if (Parent.ActiveTabPanel == (TabPanel)(object)this)
@if (Name == Parent.ActiveTab)
{
<div id="@Name" class="tab-pane fade show active" role="tabpanel">
@ChildContent
</div>
}
else
{
<div id="@Name" class="tab-pane fade" role="tabpanel">
@ChildContent
</div>
}
@code {
[CascadingParameter]
private TabControl Parent { get; set; }
private TabStrip Parent { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public string Text { get; set; }
public string Name { get; set; } // required - name of the TabPanel
[Parameter]
public string Heading { get; set; } // optional - defaults to name if not specified
protected override void OnInitialized()
{
if (Parent == null)
throw new ArgumentNullException(nameof(Parent), "TabPanel must exist within a TabControl");
base.OnInitialized();
Parent.AddTabPanel((TabPanel)(object)this);
Parent.AddTabPanel((TabPanel)this);
}
}

View File

@ -0,0 +1,66 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleBase
@attribute [OqtaneIgnore]
<CascadingValue Value="this">
<div class="container-fluid">
<div class="form-group">
<ul class="nav nav-tabs" role="tablist">
@foreach (TabPanel tabPanel in _tabPanels)
{
<li class="nav-item">
@if (tabPanel.Name == ActiveTab)
{
<a class="nav-link active" data-toggle="tab" href="#@tabPanel.Name" role="tab" @onclick:preventDefault="true">
@DisplayHeading(tabPanel.Name, tabPanel.Heading)
</a>
}
else
{
<a class="nav-link" data-toggle="tab" href="#@tabPanel.Name" role="tab" @onclick:preventDefault="true">
@DisplayHeading(tabPanel.Name, tabPanel.Heading)
</a>
}
</li>
}
</ul>
<div class="tab-content">
<br />
@ChildContent
</div>
</div>
</div>
</CascadingValue>
@code {
private List<TabPanel> _tabPanels = new List<TabPanel>();
[Parameter]
public RenderFragment ChildContent { get; set; } // contains the TabPanels
[Parameter]
public string ActiveTab { get; set; } // optional - defaults to first TabPanel if not specified. Can also be set using a "tab=" querystring parameter.
protected override void OnInitialized()
{
if (PageState.QueryString.ContainsKey("tab"))
{
ActiveTab = PageState.QueryString["tab"];
}
}
internal void AddTabPanel(TabPanel tabPanel)
{
_tabPanels.Add(tabPanel);
if (string.IsNullOrEmpty(ActiveTab))
{
ActiveTab = tabPanel.Name;
}
StateHasChanged();
}
private string DisplayHeading(string Name, string Heading)
{
return (string.IsNullOrEmpty(Heading)) ? Name : Heading;
}
}

View File

@ -3,6 +3,10 @@
<img src="@_src" title="@_title" @onclick="SetValue" />
@code {
private bool? _value = null;
private string _title;
private string _src = string.Empty;
[Parameter]
public bool? Value { get; set; }
@ -12,10 +16,6 @@
[Parameter]
public Action<bool?> OnChange { get; set; }
bool? _value = null;
string _title;
string _src = "";
protected override void OnInitialized()
{
_value = Value;
@ -38,6 +38,7 @@
_value = true;
break;
}
SetImage();
OnChange(_value);
}
@ -57,9 +58,10 @@
break;
case null:
_src = "images/null.png";
_title = "";
_title = string.Empty;
break;
}
StateHasChanged();
}
}

View File

@ -1,16 +0,0 @@
@namespace Oqtane.Modules.Counter
@inherits ModuleBase
Current count: @currentCount
<br />
<button type="button" class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<br />
<br />
@code {
int currentCount = 0;
void IncrementCount()
{
currentCount++;
}
}

View File

@ -1,21 +0,0 @@
using System.Collections.Generic;
namespace Oqtane.Modules.Counter
{
public class Module : IModule
{
public Dictionary<string, string> Properties
{
get
{
Dictionary<string, string> properties = new Dictionary<string, string>
{
{ "Name", "Counter" },
{ "Description", "Increments a counter" },
{ "Version", "1.0.0" }
};
return properties;
}
}
}
}

View File

@ -3,123 +3,58 @@
@using Oqtane.Modules.Controls
@namespace Oqtane.Modules.HtmlText
@inherits ModuleBase
@inject IHtmlTextService HtmlTextService
@inject NavigationManager NavigationManager
@inject HttpClient http
@inject SiteState sitestate
<div class="row" style="margin-bottom: 50px;">
<div class="col @_visibleText">
<textarea class="form-control" @bind="@content" rows="10"></textarea>
</div>
<div class="col @_visibleRich">
<RichTextEditor @ref="@RichTextEditorHtml">
<ToolbarContent>
<select class="ql-header">
<option selected=""></option>
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
<option value="4"></option>
<option value="5"></option>
</select>
<span class="ql-formats">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<button class="ql-strike"></button>
</span>
<span class="ql-formats">
<select class="ql-color"></select>
<select class="ql-background"></select>
</span>
<span class="ql-formats">
<button class="ql-list" value="ordered"></button>
<button class="ql-list" value="bullet"></button>
</span>
<span class="ql-formats">
<button class="ql-link"></button>
</span>
</ToolbarContent>
</RichTextEditor>
</div>
</div>
<div class="row">
<div class="col">
@if (!RichTextEditorMode)
{
<button type="button" class="btn btn-secondary" @onclick="RichTextEditor">Rich Text Editor</button>
}
else
{
<button type="button" class="btn btn-secondary" @onclick="RawHtmlEditor">Raw HTML Editor</button>
}
@if (_content != null)
{
<RichTextEditor Content="@_content" @ref="@RichTextEditorHtml"></RichTextEditor>
<button type="button" class="btn btn-success" @onclick="SaveContent">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
</div>
</div>
<div class="row">
<div class="col">
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
</div>
</div>
@if (!string.IsNullOrEmpty(_content))
{
<br />
<br />
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
}
}
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
public override SecurityAccessLevel SecurityAccessLevel
public override string Title => "Edit Html/Text";
public override List<Resource> Resources => new List<Resource>()
{
get { return SecurityAccessLevel.Edit; }
}
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.bubble.css" },
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.snow.css" }
};
public override string Title
{
get { return "Edit Html/Text"; }
}
private RichTextEditor RichTextEditorHtml;
private string _content = null;
private string _createdby;
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
public bool RichTextEditorMode
{
get => _richTextEditorMode;
set
{
_richTextEditorMode = value;
if (_richTextEditorMode)
{
_visibleText = "d-none";
_visibleRich = "";
}
else
{
_visibleText = "";
_visibleRich = "d-none";
}
}
}
string _visibleText = "d-none";
string _visibleRich;
bool _richTextEditorMode;
RichTextEditor RichTextEditorHtml;
string content;
string createdby;
DateTime createdon;
string modifiedby;
DateTime modifiedon;
protected override async Task OnAfterRenderAsync(bool firstRender)
protected override async Task OnInitializedAsync()
{
try
{
if (firstRender)
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltext != null)
{
if (content == null)
{
RichTextEditorMode = true;
await LoadText();
_content = htmltext.Content;
_content = _content.Replace(Constants.ContentUrl, "/" + PageState.Alias.AliasId.ToString() + Constants.ContentUrl);
_createdby = htmltext.CreatedBy;
_createdon = htmltext.CreatedOn;
_modifiedby = htmltext.ModifiedBy;
_modifiedon = htmltext.ModifiedOn;
}
else
{
_content = string.Empty;
}
}
catch (Exception ex)
@ -129,65 +64,27 @@
}
}
private async Task LoadText()
{
HtmlTextService htmltextservice = new HtmlTextService(http, sitestate, NavigationManager);
HtmlTextInfo htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltext != null)
{
content = htmltext.Content;
createdby = htmltext.CreatedBy;
createdon = htmltext.CreatedOn;
modifiedby = htmltext.ModifiedBy;
modifiedon = htmltext.ModifiedOn;
if (RichTextEditorMode)
{
await RichTextEditorHtml.LoadContent(content);
StateHasChanged();
}
}
}
private async Task RichTextEditor()
{
RichTextEditorMode = true;
await RichTextEditorHtml.LoadContent(content);
StateHasChanged();
}
private async Task RawHtmlEditor()
{
content = await this.RichTextEditorHtml.GetHtml();
RichTextEditorMode = false;
StateHasChanged();
}
private async Task SaveContent()
{
if (RichTextEditorMode)
{
content = await RichTextEditorHtml.GetHtml();
}
content = content.Replace(((PageState.Alias.Path == "") ? "/~" : PageState.Alias.Path) + Constants.ContentUrl, Constants.ContentUrl);
string content = await RichTextEditorHtml.GetHtml();
content = content.Replace("/" + PageState.Alias.AliasId.ToString() + Constants.ContentUrl, Constants.ContentUrl);
try
{
HtmlTextService htmltextservice = new HtmlTextService(http, sitestate, NavigationManager);
HtmlTextInfo htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId);
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltext != null)
{
htmltext.Content = content;
await htmltextservice.UpdateHtmlTextAsync(htmltext);
await HtmlTextService.UpdateHtmlTextAsync(htmltext);
}
else
{
htmltext = new HtmlTextInfo();
htmltext.ModuleId = ModuleState.ModuleId;
htmltext.Content = content;
await htmltextservice.AddHtmlTextAsync(htmltext);
await HtmlTextService.AddHtmlTextAsync(htmltext);
}
await logger.LogInformation("Html/Text Content Saved {HtmlText}", htmltext);
NavigationManager.NavigateTo(NavigateUrl());
}
@ -197,5 +94,4 @@
AddModuleMessage("Error Saving Content", MessageType.Error);
}
}
}

View File

@ -1,30 +1,32 @@
@using Oqtane.Modules.HtmlText.Services
@using Oqtane.Modules.HtmlText.Models
@namespace Oqtane.Modules.HtmlText
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject HttpClient http
@inject SiteState sitestate
@inject IHtmlTextService HtmlTextService
@((MarkupString)content)
<br />
<ActionLink Action="Edit" />
<br /><br />
@if (PageState.EditMode)
{
<br /><ActionLink Action="Edit" /><br /><br />
}
@code {
string content = "";
public override List<Resource> Resources => new List<Resource>()
{
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
};
private string content = "";
protected override async Task OnParametersSetAsync()
{
try
{
HtmlTextService htmltextservice = new HtmlTextService(http, sitestate, NavigationManager);
HtmlTextInfo htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId);
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltext != null)
{
content = htmltext.Content;
content = content.Replace(Constants.ContentUrl, ((PageState.Alias.Path == "") ? "/~" : PageState.Alias.Path) + Constants.ContentUrl);
content = content.Replace(Constants.ContentUrl, "/" + PageState.Alias.AliasId.ToString() + Constants.ContentUrl);
}
}
catch (Exception ex)

View File

@ -1,22 +1,16 @@
using System.Collections.Generic;
using Oqtane.Models;
namespace Oqtane.Modules.HtmlText
{
public class ModuleInfo : IModule
{
public Dictionary<string, string> Properties
public ModuleDefinition ModuleDefinition => new ModuleDefinition
{
get
{
Dictionary<string, string> properties = new Dictionary<string, string>
{
{ "Name", "HtmlText" },
{ "Description", "Renders HTML or Text" },
{ "Version", "1.0.0" },
{ "ServerAssemblyName", "Oqtane.Server" }
Name = "HtmlText",
Description = "Renders HTML or Text Content",
Version = "1.0.0",
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
ReleaseVersions = "1.0.0"
};
return properties;
}
}
}
}

View File

@ -2,59 +2,42 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Oqtane.Modules.HtmlText.Models;
using Oqtane.Services;
using Oqtane.Shared;
namespace Oqtane.Modules.HtmlText.Services
{
public class HtmlTextService : ServiceBase, IHtmlTextService
public class HtmlTextService : ServiceBase, IHtmlTextService, IService
{
private readonly HttpClient _http;
private readonly NavigationManager _navigationManager;
private readonly SiteState _siteState;
public HtmlTextService(HttpClient http, SiteState siteState, NavigationManager navigationManager)
public HtmlTextService(HttpClient http, SiteState siteState) : base(http)
{
_http = http;
_siteState = siteState;
_navigationManager = navigationManager;
}
private string ApiUrl => CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "HtmlText");
private string ApiUrl => CreateApiUrl(_siteState.Alias, "HtmlText");
public async Task<HtmlTextInfo> GetHtmlTextAsync(int moduleId)
{
HtmlTextInfo htmlText;
try
{
//because GetJsonAsync() returns an error if no content exists for the ModuleId ( https://github.com/aspnet/AspNetCore/issues/14041 )
//null value is transfered as empty list
var htmlTextList = await _http.GetJsonAsync<List<HtmlTextInfo>>(ApiUrl + "/" + moduleId + "?entityid=" + moduleId);
htmlText = htmlTextList.FirstOrDefault();
}
catch
{
htmlText = null;
}
return htmlText;
var htmltext = await GetJsonAsync<List<HtmlTextInfo>>($"{ApiUrl}/{moduleId}?entityid={moduleId}");
return htmltext.FirstOrDefault();
}
public async Task AddHtmlTextAsync(HtmlTextInfo htmlText)
{
await _http.PostJsonAsync(ApiUrl + "?entityid=" + htmlText.ModuleId, htmlText);
await PostJsonAsync($"{ApiUrl}?entityid={htmlText.ModuleId}", htmlText);
}
public async Task UpdateHtmlTextAsync(HtmlTextInfo htmlText)
{
await _http.PutJsonAsync(ApiUrl + "/" + htmlText.HtmlTextId + "?entityid=" + htmlText.ModuleId, htmlText);
await PutJsonAsync($"{ApiUrl}/{htmlText.HtmlTextId}?entityid={htmlText.ModuleId}", htmlText);
}
public async Task DeleteHtmlTextAsync(int moduleId)
{
await _http.DeleteAsync(ApiUrl + "/" + moduleId + "?entityid=" + moduleId);
await DeleteAsync($"{ApiUrl}/{moduleId}?entityid={moduleId}");
}
}
}

View File

@ -1,9 +1,9 @@
using System.Collections.Generic;
using Oqtane.Models;
namespace Oqtane.Modules
{
public interface IModule
{
Dictionary<string, string> Properties { get; }
ModuleDefinition ModuleDefinition { get; }
}
}

View File

@ -6,10 +6,13 @@ using Oqtane.Services;
using System;
using Oqtane.Enums;
using Oqtane.UI;
using System.Collections.Generic;
using Microsoft.JSInterop;
using System.Linq;
namespace Oqtane.Modules
{
public class ModuleBase : ComponentBase, IModuleControl
public abstract class ModuleBase : ComponentBase, IModuleControl
{
private Logger _logger;
@ -18,6 +21,9 @@ namespace Oqtane.Modules
[Inject]
protected ILogService LoggingService { get; set; }
[Inject]
protected IJSRuntime JSRuntime { get; set; }
[CascadingParameter]
protected PageState PageState { get; set; }
@ -27,7 +33,6 @@ namespace Oqtane.Modules
[CascadingParameter]
protected ModuleInstance ModuleInstance { get; set; }
// optional interface properties
public virtual SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } set { } } // default security
@ -37,6 +42,27 @@ namespace Oqtane.Modules
public virtual bool UseAdminContainer { get { return true; } }
public virtual List<Resource> Resources { get; set; }
// base lifecycle method for handling JSInterop script registration
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
{
var scripts = new List<object>();
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
{
scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "" });
}
var interop = new Interop(JSRuntime);
await interop.IncludeScripts(scripts.ToArray());
}
}
}
// path method
public string ModulePath()
@ -87,9 +113,7 @@ namespace Oqtane.Modules
public string ContentUrl(int fileid)
{
string url = (PageState.Alias.Path == "") ? "/~" : PageState.Alias.Path;
url += Constants.ContentUrl + fileid.ToString();
return url;
return Utilities.ContentUrl(PageState.Alias, fileid);
}
// user feedback methods

View File

@ -1,42 +0,0 @@
@using Oqtane.Modules.Weather.Services
@namespace Oqtane.Modules.Weather
@inherits ModuleBase
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
WeatherForecastService forecastservice = new WeatherForecastService();
forecasts = await forecastservice.GetForecastAsync(DateTime.UtcNow);
}
}

View File

@ -1,12 +0,0 @@
using System;
namespace Oqtane.Modules.Weather
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF { get; set; }
public string Summary { get; set; }
}
}

View File

@ -1,21 +0,0 @@
using System.Collections.Generic;
namespace Oqtane.Modules.Weather
{
public class Module : IModule
{
public Dictionary<string, string> Properties
{
get
{
Dictionary<string, string> properties = new Dictionary<string, string>
{
{ "Name", "Weather" },
{ "Description", "Displays random weather using a service" },
{ "Version", "1.0.0" }
};
return properties;
}
}
}
}

View File

@ -1,10 +0,0 @@
using System;
using System.Threading.Tasks;
namespace Oqtane.Modules.Weather.Services
{
public interface IWeatherForecastService
{
Task<WeatherForecast[]> GetForecastAsync(DateTime startDate);
}
}

View File

@ -1,26 +0,0 @@
using Oqtane.Modules;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Oqtane.Modules.Weather.Services
{
public class WeatherForecastService : IWeatherForecastService
{
private static string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
var rng = new Random();
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray());
}
}
}

View File

@ -3,15 +3,10 @@
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<OutputType>Exe</OutputType>
<BlazorLinkOnBuild>false</BlazorLinkOnBuild>
<RestoreAdditionalProjectSources>
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
https://dotnet.myget.org/F/blazor-dev/api/v3/index.json;
</RestoreAdditionalProjectSources>
<LangVersion>7.3</LangVersion>
<RazorLangVersion>3.0</RazorLangVersion>
<Configurations>Debug;Release;Wasm</Configurations>
<Version>0.0.1</Version>
<Configurations>Debug;Release</Configurations>
<Version>1.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -20,23 +15,27 @@
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<RepositoryUrl>https://github.com/oqtane</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<PackageReleaseNotes>Not for production use.</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v1.0.1</PackageReleaseNotes>
<RootNamespace>Oqtane</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Wasm|AnyCPU'">
<DefineConstants>TRACE;WASM</DefineConstants>
<IsPackable>true</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Blazor" Version="3.1.0-preview4.19579.2" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="3.1.0-preview4.19579.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.1.0-preview4.19579.2" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.1.0" />
<Compile Remove="Modules\Admin\ModuleCreator\Templates\**" />
<Content Remove="Modules\Admin\ModuleCreator\Templates\**" />
<EmbeddedResource Remove="Modules\Admin\ModuleCreator\Templates\**" />
<None Remove="Modules\Admin\ModuleCreator\Templates\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.1.4" />
<PackageReference Include="System.Net.Http.Json" Version="3.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,22 +1,142 @@
namespace Oqtane
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Oqtane.Services;
using System.Reflection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using Oqtane.Modules;
using Oqtane.Shared;
using Oqtane.Providers;
using Microsoft.AspNetCore.Components.Authorization;
using System.IO.Compression;
using System.IO;
namespace Oqtane.Client
{
public class Program
{
#if DEBUG || RELEASE
public static void Main(string[] args)
public static async Task Main(string[] args)
{
}
#endif
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
HttpClient httpClient = new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)};
#if WASM
public static void Main(string[] args)
builder.Services.AddSingleton(httpClient);
builder.Services.AddOptions();
// register auth services
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<IdentityAuthenticationStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<IdentityAuthenticationStateProvider>());
// register scoped core services
builder.Services.AddScoped<SiteState>();
builder.Services.AddScoped<IInstallationService, InstallationService>();
builder.Services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
builder.Services.AddScoped<IThemeService, ThemeService>();
builder.Services.AddScoped<IAliasService, AliasService>();
builder.Services.AddScoped<ITenantService, TenantService>();
builder.Services.AddScoped<ISiteService, SiteService>();
builder.Services.AddScoped<IPageService, PageService>();
builder.Services.AddScoped<IModuleService, ModuleService>();
builder.Services.AddScoped<IPageModuleService, PageModuleService>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IProfileService, ProfileService>();
builder.Services.AddScoped<IRoleService, RoleService>();
builder.Services.AddScoped<IUserRoleService, UserRoleService>();
builder.Services.AddScoped<ISettingService, SettingService>();
builder.Services.AddScoped<IPackageService, PackageService>();
builder.Services.AddScoped<ILogService, LogService>();
builder.Services.AddScoped<IJobService, JobService>();
builder.Services.AddScoped<IJobLogService, JobLogService>();
builder.Services.AddScoped<INotificationService, NotificationService>();
builder.Services.AddScoped<IFolderService, FolderService>();
builder.Services.AddScoped<IFileService, FileService>();
builder.Services.AddScoped<ISiteTemplateService, SiteTemplateService>();
builder.Services.AddScoped<ISqlService, SqlService>();
builder.Services.AddScoped<ISystemService, SystemService>();
await LoadClientAssemblies(httpClient);
// dynamically register module contexts and repository services
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
CreateHostBuilder(args).Build().Run();
var implementationTypes = assembly.GetTypes()
.Where(item => item.GetInterfaces().Contains(typeof(IService)));
foreach (Type implementationtype in implementationTypes)
{
Type servicetype = Type.GetType(implementationtype.AssemblyQualifiedName.Replace(implementationtype.Name, "I" + implementationtype.Name));
if (servicetype != null)
{
builder.Services.AddScoped(servicetype, implementationtype); // traditional service interface
}
else
{
builder.Services.AddScoped(implementationtype, implementationtype); // no interface defined for service
}
}
public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) =>
BlazorWebAssemblyHost.CreateDefaultBuilder()
.UseBlazorStartup<Startup>();
#endif
assembly.GetInstances<IClientStartup>()
.ToList()
.ForEach(x => x.ConfigureServices(builder.Services));
}
await builder.Build().RunAsync();
}
private static async Task LoadClientAssemblies(HttpClient http)
{
// get list of loaded assemblies on the client
var assemblies = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).ToList();
// get assemblies from server and load into client app domain
var zip = await http.GetByteArrayAsync($"/~/api/Installation/load");
// asemblies and debug symbols are packaged in a zip file
using (ZipArchive archive = new ZipArchive(new MemoryStream(zip)))
{
Dictionary<string, byte[]> dlls = new Dictionary<string, byte[]>();
Dictionary<string, byte[]> pdbs = new Dictionary<string, byte[]>();
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (!assemblies.Contains(Path.GetFileNameWithoutExtension(entry.Name)))
{
using (var memoryStream = new MemoryStream())
{
entry.Open().CopyTo(memoryStream);
byte[] file = memoryStream.ToArray();
switch (Path.GetExtension(entry.Name))
{
case ".dll":
dlls.Add(entry.Name, file);
break;
case ".pdb":
pdbs.Add(entry.Name, file);
break;
}
}
}
}
foreach (var item in dlls)
{
if (pdbs.ContainsKey(item.Key))
{
Assembly.Load(item.Value, pdbs[item.Key]);
}
else
{
Assembly.Load(item.Value);
}
}
}
}
}
}

View File

@ -1,6 +1,8 @@
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
@ -28,8 +30,8 @@ namespace Oqtane.Providers
{
// get HttpClient lazily from IServiceProvider as you cannot use standard dependency injection due to the AuthenticationStateProvider being initialized prior to NavigationManager ( https://github.com/aspnet/AspNetCore/issues/11867 )
var http = _serviceProvider.GetRequiredService<HttpClient>();
string apiurl = ServiceBase.CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "User") + "/authenticate";
User user = await http.GetJsonAsync<User>(apiurl);
string apiurl = "/~/api/User/authenticate";
User user = await http.GetFromJsonAsync<User>(apiurl);
ClaimsIdentity identity = new ClaimsIdentity();
if (user.IsAuthenticated)

View File

@ -2,70 +2,54 @@
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using Oqtane.Shared;
using System.Net;
using System;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class AliasService : ServiceBase, IAliasService
{
private readonly HttpClient _http;
private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager;
public AliasService(HttpClient http, SiteState siteState, NavigationManager navigationManager)
public AliasService(HttpClient http, SiteState siteState) : base(http)
{
_http = http;
_siteState = siteState;
_navigationManager = navigationManager;
}
private string Apiurl
{
get { return CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "Alias"); }
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Alias");
public async Task<List<Alias>> GetAliasesAsync()
{
List<Alias> aliases = await _http.GetJsonAsync<List<Alias>>(Apiurl);
List<Alias> aliases = await GetJsonAsync<List<Alias>>(Apiurl);
return aliases.OrderBy(item => item.Name).ToList();
}
public async Task<Alias> GetAliasAsync(int aliasId)
{
return await _http.GetJsonAsync<Alias>(Apiurl + "/" + aliasId.ToString());
return await GetJsonAsync<Alias>($"{Apiurl}/{aliasId}");
}
public async Task<Alias> GetAliasAsync(string url, DateTime lastSyncDate)
public async Task<Alias> GetAliasAsync(string name, DateTime lastSyncDate)
{
Uri uri = new Uri(url);
string name = uri.Authority;
if (uri.Segments.Count() > 1)
{
name += "/" + uri.Segments[1];
}
if (name.EndsWith("/"))
{
name = name.Substring(0, name.Length - 1);
}
return await _http.GetJsonAsync<Alias>(Apiurl + "/name/" + WebUtility.UrlEncode(name) + "?lastsyncdate=" + lastSyncDate.ToString("yyyyMMddHHmmssfff"));
name = (string.IsNullOrEmpty(name)) ? "~" : name;
return await GetJsonAsync<Alias>($"{Apiurl}/name/{WebUtility.UrlEncode(name)}?sync={lastSyncDate.ToString("yyyyMMddHHmmssfff")}");
}
public async Task<Alias> AddAliasAsync(Alias alias)
{
return await _http.PostJsonAsync<Alias>(Apiurl, alias);
return await PostJsonAsync<Alias>(Apiurl, alias);
}
public async Task<Alias> UpdateAliasAsync(Alias alias)
{
return await _http.PutJsonAsync<Alias>(Apiurl + "/" + alias.AliasId.ToString(), alias);
return await PutJsonAsync<Alias>($"{Apiurl}/{alias.AliasId}", alias);
}
public async Task DeleteAliasAsync(int aliasId)
{
await _http.DeleteAsync(Apiurl + "/" + aliasId.ToString());
await DeleteAsync($"{Apiurl}/{aliasId}");
}
}
}

View File

@ -3,7 +3,6 @@ using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Oqtane.Models;
using Oqtane.Shared;
@ -13,24 +12,16 @@ namespace Oqtane.Services
{
public class FileService : ServiceBase, IFileService
{
private readonly HttpClient _http;
private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager;
private readonly IJSRuntime _jsRuntime;
public FileService(HttpClient http, SiteState siteState, NavigationManager navigationManager,
IJSRuntime jsRuntime)
public FileService(HttpClient http, SiteState siteState, IJSRuntime jsRuntime) : base(http)
{
_http = http;
_siteState = siteState;
_navigationManager = navigationManager;
_jsRuntime = jsRuntime;
}
private string Apiurl
{
get { return CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "File"); }
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "File");
public async Task<List<File>> GetFilesAsync(int folderId)
{
@ -39,40 +30,44 @@ namespace Oqtane.Services
public async Task<List<File>> GetFilesAsync(string folder)
{
return await _http.GetJsonAsync<List<File>>(Apiurl + "?folder=" + folder);
return await GetJsonAsync<List<File>>($"{Apiurl}?folder={folder}");
}
public async Task<List<File>> GetFilesAsync(int siteId, string folderPath)
{
if (!folderPath.EndsWith("\\")) folderPath += "\\";
if (!(folderPath.EndsWith(System.IO.Path.DirectorySeparatorChar) || folderPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar)))
{
folderPath = Utilities.PathCombine(folderPath,"\\");
}
var path = WebUtility.UrlEncode(folderPath);
return await _http.GetJsonAsync<List<File>>($"{Apiurl}/{siteId}/{path}");
return await GetJsonAsync<List<File>>($"{Apiurl}/{siteId}/{path}");
}
public async Task<File> GetFileAsync(int fileId)
{
return await _http.GetJsonAsync<File>(Apiurl + "/" + fileId.ToString());
return await GetJsonAsync<File>($"{Apiurl}/{fileId}");
}
public async Task<File> AddFileAsync(File file)
{
return await _http.PostJsonAsync<File>(Apiurl, file);
return await PostJsonAsync<File>(Apiurl, file);
}
public async Task<File> UpdateFileAsync(File file)
{
return await _http.PutJsonAsync<File>(Apiurl + "/" + file.FileId.ToString(), file);
return await PutJsonAsync<File>($"{Apiurl}/{file.FileId}", file);
}
public async Task DeleteFileAsync(int fileId)
{
await _http.DeleteAsync(Apiurl + "/" + fileId.ToString());
await DeleteAsync($"{Apiurl}/{fileId}");
}
public async Task<File> UploadFileAsync(string url, int folderId)
{
return await _http.GetJsonAsync<File>(Apiurl + "/upload?url=" + WebUtility.UrlEncode(url) + "&folderid=" +
folderId.ToString());
return await GetJsonAsync<File>($"{Apiurl}/upload?url={WebUtility.UrlEncode(url)}&folderid={folderId}");
}
public async Task<string> UploadFilesAsync(int folderId, string[] files, string id)
@ -85,7 +80,7 @@ namespace Oqtane.Services
string result = "";
var interop = new Interop(_jsRuntime);
await interop.UploadFiles(Apiurl + "/upload", folder, id);
await interop.UploadFiles($"{Apiurl}/upload", folder, id);
// uploading files is asynchronous so we need to wait for the upload to complete
bool success = false;
@ -122,7 +117,7 @@ namespace Oqtane.Services
public async Task<byte[]> DownloadFileAsync(int fileId)
{
return await _http.GetByteArrayAsync(Apiurl + "/download/" + fileId.ToString());
return await GetByteArrayAsync($"{Apiurl}/download/{fileId}");
}
}
}

View File

@ -2,7 +2,6 @@
using System.Threading.Tasks;
using System.Linq;
using System.Net.Http;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using Oqtane.Shared;
using System;
@ -13,58 +12,60 @@ namespace Oqtane.Services
{
public class FolderService : ServiceBase, IFolderService
{
private readonly HttpClient _http;
private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager;
public FolderService(HttpClient http, SiteState siteState, NavigationManager navigationManager)
public FolderService(HttpClient http, SiteState siteState) : base(http)
{
_http = http;
_siteState = siteState;
_navigationManager = navigationManager;
}
private string ApiUrl => CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "Folder");
private string ApiUrl => CreateApiUrl(_siteState.Alias, "Folder");
public async Task<List<Folder>> GetFoldersAsync(int siteId)
{
List<Folder> folders = await _http.GetJsonAsync<List<Folder>>(ApiUrl + "?siteid=" + siteId.ToString());
List<Folder> folders = await GetJsonAsync<List<Folder>>($"{ApiUrl}?siteid={siteId}");
folders = GetFoldersHierarchy(folders);
return folders;
}
public async Task<Folder> GetFolderAsync(int folderId)
{
return await _http.GetJsonAsync<Folder>(ApiUrl + "/" + folderId.ToString());
return await GetJsonAsync<Folder>($"{ApiUrl}/{folderId}");
}
public async Task<Folder> GetFolderAsync(int siteId, [NotNull] string folderPath)
{
if (!folderPath.EndsWith("\\")) folderPath += "\\";
if (!(folderPath.EndsWith(System.IO.Path.DirectorySeparatorChar) || folderPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar)))
{
folderPath = Utilities.PathCombine(folderPath, "\\");
}
var path = WebUtility.UrlEncode(folderPath);
return await _http.GetJsonAsync<Folder>($"{ApiUrl}/{siteId}/{path}");
return await GetJsonAsync<Folder>($"{ApiUrl}/{siteId}/{path}");
}
public async Task<Folder> AddFolderAsync(Folder folder)
{
return await _http.PostJsonAsync<Folder>(ApiUrl, folder);
return await PostJsonAsync<Folder>(ApiUrl, folder);
}
public async Task<Folder> UpdateFolderAsync(Folder folder)
{
return await _http.PutJsonAsync<Folder>(ApiUrl + "/" + folder.FolderId.ToString(), folder);
return await PutJsonAsync<Folder>($"{ApiUrl}/{folder.FolderId}", folder);
}
public async Task UpdateFolderOrderAsync(int siteId, int folderId, int? parentId)
{
await _http.PutJsonAsync(
ApiUrl + "/?siteid=" + siteId.ToString() + "&folderid=" + folderId.ToString() + "&parentid=" +
((parentId == null) ? "" : parentId.ToString()), null);
var parent = parentId == null
? string.Empty
: parentId.ToString();
await PutAsync($"{ApiUrl}/?siteid={siteId}&folderid={folderId}&parentid={parent}");
}
public async Task DeleteFolderAsync(int folderId)
{
await _http.DeleteAsync(ApiUrl + "/" + folderId.ToString());
await DeleteAsync($"{ApiUrl}/{folderId}");
}
private static List<Folder> GetFoldersHierarchy(List<Folder> folders)

View File

@ -1,42 +1,29 @@
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using Microsoft.AspNetCore.Components;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class InstallationService : ServiceBase, IInstallationService
{
private readonly HttpClient _http;
private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager;
public InstallationService(HttpClient http):base(http) { }
public InstallationService(HttpClient http, SiteState siteState, NavigationManager navigationManager)
private string ApiUrl => CreateApiUrl("Installation");
public async Task<Installation> IsInstalled()
{
_http = http;
_siteState = siteState;
_navigationManager = navigationManager;
return await GetJsonAsync<Installation>($"{ApiUrl}/installed");
}
private string Apiurl
public async Task<Installation> Install(InstallConfig config)
{
get { return CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "Installation"); }
return await PostJsonAsync<InstallConfig,Installation>(ApiUrl, config);
}
public async Task<GenericResponse> IsInstalled()
public async Task<Installation> Upgrade()
{
return await _http.GetJsonAsync<GenericResponse>(Apiurl + "/installed");
}
public async Task<GenericResponse> Install(string connectionstring)
{
return await _http.PostJsonAsync<GenericResponse>(Apiurl, connectionstring);
}
public async Task<GenericResponse> Upgrade()
{
return await _http.GetJsonAsync<GenericResponse>(Apiurl + "/upgrade");
return await GetJsonAsync<Installation>($"{ApiUrl}/upgrade");
}
}
}

View File

@ -1,12 +1,13 @@
using Oqtane.Models;
using System.Threading.Tasks;
using Oqtane.Shared;
namespace Oqtane.Services
{
public interface IInstallationService
{
Task<GenericResponse> IsInstalled();
Task<GenericResponse> Install(string connectionstring);
Task<GenericResponse> Upgrade();
Task<Installation> IsInstalled();
Task<Installation> Install(InstallConfig config);
Task<Installation> Upgrade();
}
}

View File

@ -1,4 +1,5 @@
using Oqtane.Models;
using Oqtane.UI;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -11,6 +12,6 @@ namespace Oqtane.Services
Task UpdateModuleDefinitionAsync(ModuleDefinition moduleDefinition);
Task InstallModuleDefinitionsAsync();
Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId);
Task LoadModuleDefinitionsAsync(int siteId);
Task CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition, int moduleId);
}
}

View File

@ -6,9 +6,9 @@ namespace Oqtane.Services
{
public interface ISettingService
{
Task<Dictionary<string, string>> GetHostSettingsAsync();
Task<Dictionary<string, string>> GetTenantSettingsAsync();
Task UpdateHostSettingsAsync(Dictionary<string, string> hostSettings);
Task UpdateTenantSettingsAsync(Dictionary<string, string> tenantSettings);
Task<Dictionary<string, string>> GetSiteSettingsAsync(int siteId);

View File

@ -6,14 +6,16 @@ namespace Oqtane.Services
{
public interface ISiteService
{
Task<List<Site>> GetSitesAsync(Alias alias);
void SetAlias(Alias alias);
Task<Site> GetSiteAsync(int siteId, Alias alias);
Task<List<Site>> GetSitesAsync();
Task<Site> AddSiteAsync(Site site, Alias alias);
Task<Site> GetSiteAsync(int siteId);
Task<Site> UpdateSiteAsync(Site site, Alias alias);
Task<Site> AddSiteAsync(Site site);
Task DeleteSiteAsync(int siteId, Alias alias);
Task<Site> UpdateSiteAsync(Site site);
Task DeleteSiteAsync(int siteId);
}
}

View File

@ -0,0 +1,11 @@
using Oqtane.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Oqtane.Services
{
public interface ISiteTemplateService
{
Task<List<SiteTemplate>> GetSiteTemplatesAsync();
}
}

View File

@ -0,0 +1,10 @@
using Oqtane.Models;
using System.Threading.Tasks;
namespace Oqtane.Services
{
public interface ISqlService
{
Task<SqlQuery> ExecuteQueryAsync(SqlQuery sqlquery);
}
}

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Oqtane.Services
{
public interface ISystemService
{
Task<Dictionary<string, string>> GetSystemInfoAsync();
}
}

View File

@ -7,9 +7,9 @@ namespace Oqtane.Services
public interface IThemeService
{
Task<List<Theme>> GetThemesAsync();
Dictionary<string, string> GetThemeTypes(List<Theme> themes);
Dictionary<string, string> GetPaneLayoutTypes(List<Theme> themes, string themeName);
Dictionary<string, string> GetContainerTypes(List<Theme> themes);
List<ThemeControl> GetThemeControls(List<Theme> themes);
List<ThemeControl> GetLayoutControls(List<Theme> themes, string themeName);
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName);
Task InstallThemesAsync();
Task DeleteThemeAsync(string themeName);
}

View File

@ -11,8 +11,6 @@ namespace Oqtane.Services
Task<User> AddUserAsync(User user);
Task<User> AddUserAsync(User user, Alias alias);
Task<User> UpdateUserAsync(User user);
Task DeleteUserAsync(int userId);

View File

@ -2,7 +2,6 @@
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using Oqtane.Shared;
@ -10,45 +9,38 @@ namespace Oqtane.Services
{
public class JobLogService : ServiceBase, IJobLogService
{
private readonly HttpClient _http;
private readonly SiteState _siteState;
private readonly NavigationManager _navigationManager;
public JobLogService(HttpClient http, SiteState siteState, NavigationManager navigationManager)
public JobLogService(HttpClient http, SiteState siteState) : base(http)
{
_http = http;
_siteState = siteState;
_navigationManager = navigationManager;
}
private string Apiurl
{
get { return CreateApiUrl(_siteState.Alias, _navigationManager.Uri, "JobLog"); }
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "JobLog");
public async Task<List<JobLog>> GetJobLogsAsync()
{
List<JobLog> joblogs = await _http.GetJsonAsync<List<JobLog>>(Apiurl);
List<JobLog> joblogs = await GetJsonAsync<List<JobLog>>(Apiurl);
return joblogs.OrderBy(item => item.StartDate).ToList();
}
public async Task<JobLog> GetJobLogAsync(int jobLogId)
{
return await _http.GetJsonAsync<JobLog>(Apiurl + "/" + jobLogId.ToString());
return await GetJsonAsync<JobLog>($"{Apiurl}/{jobLogId}");
}
public async Task<JobLog> AddJobLogAsync(JobLog joblog)
{
return await _http.PostJsonAsync<JobLog>(Apiurl, joblog);
return await PostJsonAsync<JobLog>(Apiurl, joblog);
}
public async Task<JobLog> UpdateJobLogAsync(JobLog joblog)
{
return await _http.PutJsonAsync<JobLog>(Apiurl + "/" + joblog.JobLogId.ToString(), joblog);
return await PutJsonAsync<JobLog>($"{Apiurl}/{joblog.JobLogId}", joblog);
}
public async Task DeleteJobLogAsync(int jobLogId)
{
await _http.DeleteAsync(Apiurl + "/" + jobLogId.ToString());
await DeleteAsync($"{Apiurl}/{jobLogId}");
}
}
}

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