Compare commits
756 Commits
Author | SHA1 | Date | |
---|---|---|---|
a6228f3704 | |||
572f2f6be1 | |||
db63447052 | |||
37c418a869 | |||
b3b39f583a | |||
92c554e854 | |||
29fe3dfd0b | |||
985e50d415 | |||
11150b6a10 | |||
c499acdc4a | |||
b24e3252d9 | |||
e15787b1e4 | |||
d5f19d97e2 | |||
5543a4aeed | |||
9c333232e2 | |||
d52b95ea23 | |||
ef4fbcbb8a | |||
aa454b411f | |||
543e9339c7 | |||
7fff5c0d18 | |||
fa79f3f6fa | |||
c098839881 | |||
8d0d88c1b9 | |||
2b6ba0f410 | |||
11235009c0 | |||
4b05f7fdad | |||
338b0ae509 | |||
a437082952 | |||
ca9aba7b3b | |||
fe9f189734 | |||
018ac612f4 | |||
5bde40ec2b | |||
4d5780c192 | |||
ff6a810ad5 | |||
feec01ba00 | |||
1f05d12ef5 | |||
31aba14507 | |||
bbd6f13f36 | |||
68edbbbdb9 | |||
eb5a0dc1c9 | |||
7cea4f1792 | |||
c57c6abb1b | |||
a25b706c7b | |||
5d077e843d | |||
65bf3e9899 | |||
51ba3a01f5 | |||
f9ca611b8b | |||
a49b8728fd | |||
9234b91089 | |||
f3fcef52dd | |||
7f8b741981 | |||
f1791a709c | |||
30307fb05e | |||
57d443be8d | |||
84844c5043 | |||
9000f05961 | |||
6bef9b5c6e | |||
ffef1f4820 | |||
10c7bdbcaa | |||
e8f9888a41 | |||
8bac702be6 | |||
128bcecfe3 | |||
1390b3c489 | |||
a0f41341ac | |||
8ffa7ef7ff | |||
deb4607081 | |||
49c62f80e8 | |||
139793f3c0 | |||
f237cb9655 | |||
9f18c460d8 | |||
306a41b442 | |||
b53f54295d | |||
7e4f066694 | |||
90d72489d9 | |||
045c455324 | |||
60da903360 | |||
6d2a71f37e | |||
c8f60a12a4 | |||
11b2d3aa43 | |||
3d9c81d850 | |||
8ccb1a24f8 | |||
48c6796128 | |||
fc403f920b | |||
ca19496b5c | |||
0ae38f8a40 | |||
ad868ba841 | |||
f2aa39aa85 | |||
e76e0fc351 | |||
a348913888 | |||
5507006c53 | |||
994429f098 | |||
8efdcb9c49 | |||
db9a40db2b | |||
25667499e6 | |||
a728cd2d91 | |||
3f5f3ef10b | |||
0d708124c2 | |||
d31f73df14 | |||
3fed45438b | |||
8aa967fa1b | |||
6eaa3e342c | |||
6fc9e60f62 | |||
c39ffcf51c | |||
6f60a91f4c | |||
8031df6f28 | |||
da1e859fda | |||
8d4d25f1d1 | |||
6aff27778d | |||
ca2dcbfec0 | |||
24b666a382 | |||
9e34295529 | |||
10c55d056b | |||
753ab3bdd7 | |||
feee8def6f | |||
c208f12f8c | |||
dc926bf838 | |||
55a76b5204 | |||
53b837e763 | |||
3a551cdf25 | |||
c0c7f87dc9 | |||
ac77fd138b | |||
30d6e9d67c | |||
47db4334a1 | |||
fce97179e1 | |||
4f16cd2d01 | |||
fa587691b1 | |||
e0044658f9 | |||
53de1ddb36 | |||
da7b046092 | |||
d888d83a98 | |||
430f83e8e9 | |||
e7acd14faa | |||
1b00fa74bc | |||
4d572d8173 | |||
dbda85d8d9 | |||
95cb5dd66c | |||
f64e1c3a6a | |||
26a686c412 | |||
2505383f53 | |||
1a1e9ac6be | |||
7f20a3179e | |||
46431f0187 | |||
1ff8ec78c9 | |||
7840230c62 | |||
523db0a005 | |||
cc906d49ba | |||
fc23af89d3 | |||
5d8829ba63 | |||
31ccd80894 | |||
bac2234616 | |||
bd61db76a3 | |||
bc99e3b992 | |||
b7314b0813 | |||
4759bd569f | |||
b88c28f864 | |||
774ccb05f8 | |||
0ac48cba34 | |||
e36880fe3a | |||
713cf5de2c | |||
0fa336411f | |||
8ebdb09d68 | |||
40bc53001e | |||
b1656d1eea | |||
7aa54bf979 | |||
231f9bca84 | |||
e4f8596c19 | |||
020b7233d0 | |||
85fc0b3e2f | |||
5dcc7c14f3 | |||
7993d27b11 | |||
1f8c54ce74 | |||
73a414a34b | |||
8fa19c4a51 | |||
0667ae3e15 | |||
db1d00cd07 | |||
b27f092bef | |||
4eaea8e586 | |||
89cd7d3bbb | |||
2fff1d8d21 | |||
850631f00e | |||
1cea8846cf | |||
af48a48559 | |||
655c1762aa | |||
f706ccfd87 | |||
71e4c7f117 | |||
ad6182f4bd | |||
86bf0f65b0 | |||
7742f7747d | |||
eb998c41f2 | |||
657bd7c97c | |||
c8286148c1 | |||
e6ba2cce62 | |||
6105ff44b4 | |||
72da77be01 | |||
4c29b31f1b | |||
6e640108ed | |||
157322441d | |||
61d967e6af | |||
99f2158e55 | |||
1cba78cc4e | |||
1770c1ee11 | |||
a57fbea0cc | |||
f0c27c83f1 | |||
7873ca564c | |||
5ebc1fec24 | |||
f2559b7d4d | |||
1ee92a248e | |||
8376f98f21 | |||
810a3e0171 | |||
2eac9c3795 | |||
75f2425668 | |||
2dd1d7e926 | |||
5bb05a0a51 | |||
bc2c5b00c6 | |||
09f5e158dd | |||
4656471a0a | |||
69d58a4273 | |||
53a27677d4 | |||
f243ad0348 | |||
b4ce6bbb42 | |||
fa32937045 | |||
812e5f3c8e | |||
e2981e802c | |||
4ae4705c73 | |||
fbf4b12713 | |||
e4ece3e0dc | |||
9f231421be | |||
391827222e | |||
c1721bd1a1 | |||
f6630ae241 | |||
424cab64a8 | |||
b4fdbb5e48 | |||
fbf62ca30d | |||
05d2096fb8 | |||
7683af81bc | |||
bad10b3812 | |||
9f9522c2ed | |||
62879c3e52 | |||
45610f8dd7 | |||
18102cbd78 | |||
262d6a1529 | |||
1124ddaf90 | |||
981add3872 | |||
8d4b30140e | |||
b9c59137a8 | |||
0b1c7e06ca | |||
fcaf80cba6 | |||
6358b9eabb | |||
70a3fab1ff | |||
bdf86ace86 | |||
d57132d1e4 | |||
a6e87abf99 | |||
f1771610fe | |||
a88ea9780f | |||
bca0866d72 | |||
cebed93abf | |||
ee2b2e3569 | |||
cb8e9ee244 | |||
486184b16c | |||
9f9bd1988f | |||
ba1bfd1bc0 | |||
e12926e971 | |||
5b4db0de3b | |||
70ff55faa6 | |||
f2bd47d8bc | |||
e2b9c9e98e | |||
b0791a594f | |||
ea5eaa6ed2 | |||
ec3fd1d585 | |||
d76de22977 | |||
c0e3483cc7 | |||
0994cdf3b6 | |||
a76fd82262 | |||
2f919c7d69 | |||
f12592731b | |||
4a20e1a25d | |||
cc7111c3ff | |||
81972aed62 | |||
5e2092c6d4 | |||
d136f8ac91 | |||
5b23917940 | |||
2cda0a3798 | |||
f315ad1ce9 | |||
49f1c273c2 | |||
8518476c87 | |||
a34ed756db | |||
a48232c4e3 | |||
ac65e38390 | |||
eab3a753f5 | |||
9e5922e121 | |||
bf57b23776 | |||
8f4a20fd46 | |||
b3716da5ac | |||
2c129fd800 | |||
6fb18e7a25 | |||
38d28d6944 | |||
a187e1a7a2 | |||
7d7a19c7c2 | |||
6a2ae2153a | |||
f50ba1a91e | |||
b09575dbd6 | |||
c52ee3d91d | |||
1ced5c0425 | |||
e399a5c9b1 | |||
08dff5fb67 | |||
912760f2a7 | |||
4b62fdbf93 | |||
df593d43a7 | |||
89b1fba771 | |||
5505c91ae0 | |||
cc720ff399 | |||
29f07f6c56 | |||
a69e197a1f | |||
6dddd8eff8 | |||
51aada8922 | |||
b47bf40e8f | |||
48151bf365 | |||
659950996d | |||
6e656a4d0a | |||
bf308dd13d | |||
982f3b1943 | |||
7a4ea8cf1b | |||
7c0482a87c | |||
101ededd89 | |||
a8cbc0040e | |||
ed91bb445b | |||
f158a222f4 | |||
46bcad1fca | |||
5e147afb9f | |||
b061d4593f | |||
3fa520b4ef | |||
2df05b4afd | |||
e0569a6748 | |||
2e6ab398d9 | |||
94b03d2a6b | |||
f84fe30bb6 | |||
049ddef531 | |||
a1a214c742 | |||
c40a483ffa | |||
aff99acfae | |||
628129c08d | |||
679d34dfdf | |||
b2f65903ae | |||
2daefe0382 | |||
1214a11704 | |||
e55e0118c2 | |||
a1ac81e907 | |||
14ad68bf69 | |||
e3118c6e99 | |||
b41aeab8f8 | |||
1a738b358e | |||
f4b1e8035b | |||
324e985247 | |||
60faacd7d0 | |||
d4a4d7c346 | |||
189f8f1d27 | |||
ed353461da | |||
e9330d6c62 | |||
f53e7cc3f6 | |||
4f4258d532 | |||
c80910f355 | |||
12470ab178 | |||
704e091e9b | |||
f30f1e5c1f | |||
0741ce2197 | |||
fc81bae9b7 | |||
3fa68e4f96 | |||
05a767c7be | |||
8c1e8f6377 | |||
0fbae8d7da | |||
cec4b339f5 | |||
1a7656d8ee | |||
e173815810 | |||
620c768e05 | |||
7740679077 | |||
1ebc8ebff3 | |||
fa4fac70d5 | |||
8c83a18f93 | |||
a151ecfda0 | |||
dec0c0649c | |||
a356f893ac | |||
e2af4f74c3 | |||
99022b76e5 | |||
9dd6dc7523 | |||
6f588200d7 | |||
f3dbeae28e | |||
9f70361298 | |||
534353ce13 | |||
3f391a7354 | |||
0dd0752710 | |||
710fae4b0e | |||
de6c57a7ee | |||
7eee1fcd6a | |||
1fd2aedf96 | |||
ffdd7c063b | |||
a87af264eb | |||
3640cd2fdd | |||
f7cf25c4bb | |||
77dbd0d4c7 | |||
5a77c83e68 | |||
0a6763e08c | |||
b5aa206670 | |||
dbb4d9b64b | |||
6775edfd66 | |||
b06750ed65 | |||
57879c1891 | |||
65b55a76f2 | |||
8562a68306 | |||
160da46b5a | |||
ae5f70a739 | |||
4456e57466 | |||
24cd090c61 | |||
4f849f5d5f | |||
db2e86e84c | |||
14748ce2b3 | |||
527509732c | |||
aa9214477c | |||
db24ed8b55 | |||
349d1849d9 | |||
188be2fa8c | |||
5c4d7df734 | |||
37de18c670 | |||
0001e3844b | |||
65f171f701 | |||
c4308c239c | |||
2b6af3cb37 | |||
c5a16fbbc1 | |||
1db83f509b | |||
2a06304a2c | |||
7bbe684135 | |||
a996a88fc4 | |||
8cf9e7db51 | |||
ed981c67b7 | |||
6a77a0a5b9 | |||
bfb4b4431b | |||
3de44c0335 | |||
37afd1aec9 | |||
b2ac561673 | |||
c9bf7d9138 | |||
153a689bdb | |||
26b88f1a22 | |||
c66a5d028f | |||
8441c95a5c | |||
e0e32b0199 | |||
2bb76564e9 | |||
86ec25d4de | |||
ed9929963c | |||
36f50118ac | |||
72ddf27504 | |||
9bd36931ff | |||
056ef7a3d5 | |||
e483945d05 | |||
7a9c637e03 | |||
09ce543ea6 | |||
0ef24ebc3f | |||
a4419d3af6 | |||
935983c02a | |||
bd54ce5017 | |||
af6ed78b8e | |||
f72438996d | |||
9db2a55a5a | |||
950d90badb | |||
1864d180af | |||
0e82e98382 | |||
46023d35dc | |||
90d2e0a40b | |||
5f884e0796 | |||
16477052e2 | |||
66a05603f7 | |||
fe2a883386 | |||
ca7fdaa125 | |||
1283ec2008 | |||
d1f78f9048 | |||
45f43bfade | |||
4793ab4bc9 | |||
88b174dea8 | |||
06ca382bd7 | |||
b09175a8db | |||
677f68b08d | |||
8058b8dba4 | |||
4bc26f13c1 | |||
e6cf77e724 | |||
f8737c112e | |||
74b72ed9d4 | |||
4950391201 | |||
64a38d6e45 | |||
e2d8ee53f8 | |||
0204ff8dd5 | |||
4630ee6e93 | |||
c4f2abf143 | |||
e7444a0194 | |||
ffed7305ed | |||
334054bcd4 | |||
5bb98eb5b2 | |||
e842bd882a | |||
74bfb46f73 | |||
cd45bf4b70 | |||
51600bbcb0 | |||
8811a9bcaa | |||
4521f8a774 | |||
5b427783f8 | |||
9508983b15 | |||
fd09912cd7 | |||
01cc8584b6 | |||
c0b104e7c8 | |||
9a82021a82 | |||
1fb54a0b0f | |||
aa5ea61638 | |||
a59ec0258b | |||
b403f5cf71 | |||
0ac6a62b86 | |||
ed3743d3b6 | |||
3468cba000 | |||
5a4cdc5354 | |||
af4e19a57e | |||
26bb743679 | |||
96cc726e22 | |||
f4b00b01d0 | |||
127b2ca86d | |||
4b8b93e1b8 | |||
3aea412fe9 | |||
2aef96ad4f | |||
ec0a77230c | |||
b35e4bddd0 | |||
aa32beb341 | |||
efafe89b42 | |||
5ef2e49d9c | |||
1cfbf61a30 | |||
2bb5494b84 | |||
e8a41ccb47 | |||
7184f7f635 | |||
cc5727b7fa | |||
7f3d6ef6a5 | |||
44ce68097b | |||
d976cc6c19 | |||
d19d7d2a43 | |||
9bfaa02f97 | |||
2d9396b245 | |||
56e0da64ee | |||
997e9213f2 | |||
366569a23b | |||
36d5747b4f | |||
ea026c726c | |||
1e71e32c74 | |||
ed729bbd4f | |||
1a925221b7 | |||
af7b4db062 | |||
cfefe35e3f | |||
8d7845a44d | |||
3a15e6e5e9 | |||
3b8a51e855 | |||
f2cb34cc35 | |||
723ce62a34 | |||
2c9a2ea021 | |||
2be008d6d1 | |||
7fb51bdd0a | |||
abdbe3694f | |||
bd87e5012f | |||
55e18f2364 | |||
655e84072d | |||
ab5409d5b6 | |||
5a5da6486c | |||
7e99252429 | |||
10e0dcef8b | |||
80c8433aad | |||
5b0ae372f8 | |||
b5a1b529ab | |||
af821dcd9a | |||
10d3c81520 | |||
e3811b453a | |||
ca0fb05baa | |||
2b4b01bf6e | |||
3a1244bddc | |||
b8fd922b19 | |||
03f856025e | |||
45f04d24c3 | |||
2435d610c7 | |||
06572bcd14 | |||
3fab79afc0 | |||
2b7dd3fed5 | |||
d65efed032 | |||
c6896ea936 | |||
b7a41bddec | |||
6fd80c3737 | |||
0aa690b3b1 | |||
6d5bcfc6ed | |||
b60de69fa5 | |||
d991b57d08 | |||
1133d7fcba | |||
6fbf0383bb | |||
0296230219 | |||
dedfbba27a | |||
dc5441da07 | |||
585648b7f3 | |||
cd0ee1c26d | |||
d7a7be5af4 | |||
13e4267c11 | |||
15bc47e3e8 | |||
1a4380dcd7 | |||
5ace34b5cd | |||
f010c0f1fa | |||
2c721ad5dd | |||
8a7c2ce2c2 | |||
b2a7b813de | |||
e85cf04b99 | |||
ab6fa48172 | |||
c81905882f | |||
f0d31c1114 | |||
497b255216 | |||
d96286d771 | |||
2441647d75 | |||
77b780d631 | |||
cdd03bf3d4 | |||
e786c35f7d | |||
e83399acb1 | |||
ffea9e3210 | |||
f71a3a1ce3 | |||
a5ccc23604 | |||
1ed4c8a094 | |||
4a74549c1b | |||
a499cfb98f | |||
01038c8296 | |||
7407f79b3d | |||
a845dd1976 | |||
9d7549da70 | |||
f5cc61384f | |||
844778d36a | |||
871b0a274e | |||
737740a3ca | |||
ae8d600600 | |||
2f1691bfb0 | |||
a3d25f91c8 | |||
ff84b50817 | |||
0be8242284 | |||
e25a6259ea | |||
1578f82efb | |||
b5f75f0c5e | |||
601caab3b6 | |||
6d3092f440 | |||
ef27937c7a | |||
f4a7b79c4f | |||
2531776a48 | |||
ced80419aa | |||
ad2816f4e8 | |||
3528b8c674 | |||
80c83c626d | |||
6a355f2aea | |||
7d94e4a53a | |||
823c04742e | |||
043fb1abd1 | |||
f01e85b690 | |||
7eb1298847 | |||
a5480c9a96 | |||
f948600e86 | |||
420182b9bf | |||
8c430ce1a6 | |||
d3717dbe19 | |||
caa83d769f | |||
365f87828f | |||
f780887866 | |||
43627d4bb8 | |||
5d7b276cd1 | |||
23597eb997 | |||
b6948367f8 | |||
db6dd5abee | |||
702eb9e466 | |||
3c99006226 | |||
aaaf5683a5 | |||
92aa2236c0 | |||
d2592f72d6 | |||
27120d6cc9 | |||
a2669d35c3 | |||
574164081b | |||
00c2f8dcd8 | |||
0202bf60e5 | |||
16436a171b | |||
4cf4e0eabd | |||
5edb98dfb4 | |||
899bf22e15 | |||
9a33167a6c | |||
2dc068aa21 | |||
0f2aa4d2e1 | |||
a699f5c7bc | |||
ab807de3c0 | |||
68514bcb36 | |||
422bf8da59 | |||
de92dc93dd | |||
5a91b143b6 | |||
c745e85706 | |||
0f698e0c50 | |||
cd16d77bf0 | |||
fdbdd0ef4c | |||
71485f4a82 | |||
013056a6e5 | |||
263498fbdc | |||
f46ac2c007 | |||
c23841b6db | |||
18b1b5fca5 | |||
6707ac2697 | |||
d85a2fc8ce | |||
a8997e8f17 | |||
c8a22d9537 | |||
910669f786 | |||
89312c6796 | |||
a6aa96fdb0 | |||
7deb0b06af | |||
784f3771b3 | |||
80316824f7 | |||
cbaebb7b7c | |||
97d3764b6e | |||
002f8117cb | |||
0dfdb12431 | |||
d77e898929 | |||
4c937be884 | |||
c25cce4398 | |||
58c422285a | |||
f2f22f35e8 | |||
15867a7807 | |||
22e3161a9b | |||
b0c8203b24 | |||
e2c404d8bb | |||
5ee1731c92 | |||
06e8d3b660 | |||
f09709aedb | |||
598d5decac | |||
7832a6053e | |||
588748230e | |||
8668165c72 | |||
a967332f89 | |||
6719d242bd | |||
3565185808 | |||
ce51262197 | |||
992a786c2b | |||
038df95aa0 | |||
4ebd660de2 | |||
a9ea41a488 | |||
196594b490 | |||
1516d5af10 | |||
ffcd1595a9 | |||
42e5c6e111 | |||
8a9651dc50 | |||
4be2f4f2d9 | |||
369bf7a235 | |||
136545b404 | |||
73ea17ae0f | |||
23010acef4 | |||
4f74962ce2 | |||
7f978c7845 | |||
bf175984f3 | |||
4b17847ea5 | |||
2addcc3ab5 | |||
370b39a139 | |||
7b7e64576f | |||
286928d59e | |||
cc65555c3d | |||
63e3923349 |
@ -1,2 +0,0 @@
|
|||||||
[config]
|
|
||||||
project = Oqtane.Server/Oqtane.Server.csproj
|
|
25
.gitea/workflows/build-container.yml
Normal file
25
.gitea/workflows/build-container.yml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: build-docker-imge
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build the docker container
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: "Git clone"
|
||||||
|
run: git clone ${{ gitea.server_url }}/${{ gitea.repository }}.git .
|
||||||
|
- name: "Git checkout"
|
||||||
|
run: git checkout "${{ gitea.sha }}"
|
||||||
|
- uses: aevea/action-kaniko@master
|
||||||
|
name: Run Kaniko to build our api docker container.
|
||||||
|
with:
|
||||||
|
image: kocoded/oqtane.framework
|
||||||
|
tag: ${{ git.workflow_sha }}
|
||||||
|
tag_with_latest: github.ref == 'refs/heads/master'
|
||||||
|
registry: git.kocoder.xyz
|
||||||
|
username: ${{ secrets.CI_RUNNER_USER }}
|
||||||
|
password: ${{ secrets.CI_RUNNER_TOKEN }}
|
||||||
|
build_file: Dockerfile
|
||||||
|
target: deploy
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -22,6 +22,9 @@ Oqtane.Server/Packages
|
|||||||
Oqtane.Server/wwwroot/Content
|
Oqtane.Server/wwwroot/Content
|
||||||
Oqtane.Server/wwwroot/Packages/*.log
|
Oqtane.Server/wwwroot/Packages/*.log
|
||||||
|
|
||||||
|
Oqtane.Server/wwwroot/_content/*
|
||||||
|
!Oqtane.Server/wwwroot/_content/Placeholder.txt
|
||||||
|
|
||||||
Oqtane.Server/wwwroot/Modules/*
|
Oqtane.Server/wwwroot/Modules/*
|
||||||
!Oqtane.Server/wwwroot/Modules/Oqtane.Modules.*
|
!Oqtane.Server/wwwroot/Modules/Oqtane.Modules.*
|
||||||
!Oqtane.Server/wwwroot/Modules/Templates
|
!Oqtane.Server/wwwroot/Modules/Templates
|
||||||
|
24
CONTRIBUTING.md
Normal file
24
CONTRIBUTING.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Contributing to Oqtane
|
||||||
|
|
||||||
|
## How to Contribute
|
||||||
|
|
||||||
|
We track all of our issues on Github. If you want to contribute, everything starts with an issue. If you don't have an issue yet, you can add one. Then a core contributor will tag it as either an enhancement [ENH] or a bug [BUG]. Tagged issues are open for contribution.
|
||||||
|
|
||||||
|
## Use GitHub-flow process
|
||||||
|
- Make a comment on the issue that you intend to work on it and read all the comments to gain a full understanding.
|
||||||
|
- Fork the repository
|
||||||
|
- Create a new branch and update your comment on the issue with a llink to the branch
|
||||||
|
- Make your changes and commit them
|
||||||
|
- Push to the branch
|
||||||
|
- Create a pull request
|
||||||
|
|
||||||
|
## Reporting Bugs
|
||||||
|
|
||||||
|
- Check if the issue has already been reported.
|
||||||
|
- Open a new issue if it hasn’t been reported.
|
||||||
|
|
||||||
|
## Requesting Features
|
||||||
|
|
||||||
|
- Use the feature request template in the Issues tab.
|
||||||
|
|
||||||
|
Thank you for contributing!
|
24
Dockerfile
Normal file
24
Dockerfile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Build
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||||
|
|
||||||
|
WORKDIR /source
|
||||||
|
|
||||||
|
COPY --link . .
|
||||||
|
|
||||||
|
RUN dotnet restore /source/Oqtane.sln
|
||||||
|
|
||||||
|
RUN dotnet build "/source/Oqtane.sln" -c Release -o /source/build/
|
||||||
|
|
||||||
|
# Publish
|
||||||
|
FROM build AS publish
|
||||||
|
|
||||||
|
RUN dotnet publish "Oqtane.Server/Oqtane.Server.csproj" -c Release -o /source/publish/
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS deploy
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
|
||||||
|
COPY --from=publish /source/publish/ /app/
|
||||||
|
ENTRYPOINT ["dotnet", "Oqtane.Server.dll"]
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018-2024 .NET Foundation
|
Copyright (c) 2018-2025 .NET Foundation
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -51,6 +51,10 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddScoped<IUrlMappingService, UrlMappingService>();
|
services.AddScoped<IUrlMappingService, UrlMappingService>();
|
||||||
services.AddScoped<IVisitorService, VisitorService>();
|
services.AddScoped<IVisitorService, VisitorService>();
|
||||||
services.AddScoped<ISyncService, SyncService>();
|
services.AddScoped<ISyncService, SyncService>();
|
||||||
|
services.AddScoped<ILocalizationCookieService, LocalizationCookieService>();
|
||||||
|
services.AddScoped<ICookieConsentService, CookieConsentService>();
|
||||||
|
services.AddScoped<IOutputCacheService, OutputCacheService>();
|
||||||
|
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
||||||
|
|
||||||
// providers
|
// providers
|
||||||
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();
|
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();
|
||||||
|
119
Oqtane.Client/Installer/Controls/AzureSqlConfig.razor
Normal file
119
Oqtane.Client/Installer/Controls/AzureSqlConfig.razor
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
@namespace Oqtane.Installer.Controls
|
||||||
|
@implements Oqtane.Interfaces.IDatabaseConfigControl
|
||||||
|
@inject IStringLocalizer<SqlServerConfig> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="server" HelpText="Enter the database server name. This might include a port number as well if you are using a cloud service." ResourceKey="Server">Server:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="server" type="text" class="form-control" @bind="@_server" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="database" HelpText="Enter the name of the database" ResourceKey="Database">Database:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="database" type="text" class="form-control" @bind="@_database" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="security" HelpText="Select your security method" ResourceKey="Security">Security:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="security" class="form-select custom-select" @bind="@_security">
|
||||||
|
<option value="integrated" selected>@Localizer["Integrated"]</option>
|
||||||
|
<option value="custom">@Localizer["Custom"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (_security == "custom")
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="uid" HelpText="Enter the username to use for the database" ResourceKey="Uid">User Id:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="uid" type="text" class="form-control" @bind="@_uid" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="pwd" HelpText="Enter the password to use for the database" ResourceKey="Pwd">Password:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="pwd" type="@_passwordType" class="form-control" @bind="@_pwd" autocomplete="new-password" />
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglePassword</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="encryption" HelpText="Specify if you are using an encrypted database connection. It is highly recommended to use encryption in a production environment." ResourceKey="Encryption">Encryption:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="encryption" class="form-select custom-select" @bind="@_encryption">
|
||||||
|
<option value="true">@SharedLocalizer["True"]</option>
|
||||||
|
<option value="false">@SharedLocalizer["False"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (_encryption == "true")
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="trustservercertificate" HelpText="Specify the type of certificate you are using for encryption. Verifiable is equivalent to False. Self Signed is equivalent to True." ResourceKey="TrustServerCertificate">Certificate:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="encryption" class="form-select custom-select" @bind="@_trustservercertificate">
|
||||||
|
<option value="true">@Localizer["Self Signed"]</option>
|
||||||
|
<option value="false">@Localizer["Verifiable"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private string _server = "tcp:{SQL Server Name}.database.windows.net,1433";
|
||||||
|
private string _database = "{SQL Database Name}";
|
||||||
|
private string _security = "custom";
|
||||||
|
private string _uid = "{SQL Administrator Login}";
|
||||||
|
private string _pwd = String.Empty;
|
||||||
|
private string _passwordType = "password";
|
||||||
|
private string _togglePassword = string.Empty;
|
||||||
|
private string _encryption = "true";
|
||||||
|
private string _trustservercertificate = "false";
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetConnectionString()
|
||||||
|
{
|
||||||
|
var connectionString = String.Empty;
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(_server) && !String.IsNullOrEmpty(_database))
|
||||||
|
{
|
||||||
|
connectionString = $"Data Source={_server};Initial Catalog={_database};";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_security == "integrated")
|
||||||
|
{
|
||||||
|
connectionString += "Integrated Security=SSPI;";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connectionString += $"User ID={_uid};Password={_pwd};";
|
||||||
|
}
|
||||||
|
connectionString += $"Encrypt={_encryption};";
|
||||||
|
connectionString += $"TrustServerCertificate={_trustservercertificate};";
|
||||||
|
|
||||||
|
return connectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TogglePassword()
|
||||||
|
{
|
||||||
|
if (_passwordType == "password")
|
||||||
|
{
|
||||||
|
_passwordType = "text";
|
||||||
|
_togglePassword = SharedLocalizer["HidePassword"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_passwordType = "password";
|
||||||
|
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="server" HelpText="Enter the database server name. This might include a port number as well if you are using a cloud service (ie. servername.database.windows.net,1433) " ResourceKey="Server">Server:</Label>
|
<Label Class="col-sm-3" For="server" HelpText="Enter the database server name. This might include a port number as well if you are using a cloud service." ResourceKey="Server">Server:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="server" type="text" class="form-control" @bind="@_server" />
|
<input id="server" type="text" class="form-control" @bind="@_server" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="mx-auto text-center">
|
<div class="mx-auto text-center">
|
||||||
<img src="oqtane-black.png" />
|
<img src="oqtane-black.png" />
|
||||||
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET 8)</div>
|
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET @Environment.Version.Major)</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr class="app-rule" />
|
<hr class="app-rule" />
|
||||||
@ -71,14 +71,14 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="username" HelpText="Provide a username for the primary user account" ResourceKey="Username">Username:</Label>
|
<Label Class="col-sm-3" For="username" HelpText="Provide a username for the primary user account" ResourceKey="Username">Username:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="username" type="text" class="form-control" @bind="@_hostUsername" />
|
<input id="username" type="text" class="form-control" maxlength="256" @bind="@_hostUsername" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="password" HelpText="Provide a password for the primary user account" ResourceKey="Password">Password:</Label>
|
<Label Class="col-sm-3" For="password" HelpText="Provide a password for the primary user account" ResourceKey="Password">Password:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordType" class="form-control" @bind="@_hostPassword" autocomplete="new-password" />
|
<input id="password" type="@_passwordType" class="form-control" maxlength="256" @bind="@_hostPassword" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglePassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglePassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -87,7 +87,7 @@
|
|||||||
<Label Class="col-sm-3" For="confirm" HelpText="Please confirm the password entered above by entering it again" ResourceKey="Confirm">Confirm:</Label>
|
<Label Class="col-sm-3" For="confirm" HelpText="Please confirm the password entered above by entering it again" ResourceKey="Confirm">Confirm:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_confirmPasswordType" class="form-control" @bind="@_confirmPassword" autocomplete="new-password" />
|
<input id="confirm" type="@_confirmPasswordType" class="form-control" maxlength="256" @bind="@_confirmPassword" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleConfirmPassword" tabindex="-1">@_toggleConfirmPassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleConfirmPassword" tabindex="-1">@_toggleConfirmPassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -95,7 +95,13 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="email" HelpText="Provide the email address for the host user account" ResourceKey="Email">Email:</Label>
|
<Label Class="col-sm-3" For="email" HelpText="Provide the email address for the host user account" ResourceKey="Email">Email:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input type="text" class="form-control" @bind="@_hostEmail" />
|
<input type="text" class="form-control" maxlength="256" @bind="@_hostEmail" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="name" HelpText="Provide the full name of the host user" ResourceKey="Name">Full Name:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="text" class="form-control" maxlength="50" @bind="@_hostName" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -153,132 +159,134 @@
|
|||||||
private string _toggleConfirmPassword = string.Empty;
|
private string _toggleConfirmPassword = string.Empty;
|
||||||
private string _confirmPassword = string.Empty;
|
private string _confirmPassword = string.Empty;
|
||||||
private string _hostEmail = string.Empty;
|
private string _hostEmail = string.Empty;
|
||||||
|
private string _hostName = string.Empty;
|
||||||
private List<SiteTemplate> _templates;
|
private List<SiteTemplate> _templates;
|
||||||
private string _template = Constants.DefaultSiteTemplate;
|
private string _template = Constants.DefaultSiteTemplate;
|
||||||
private bool _register = true;
|
private bool _register = true;
|
||||||
private string _message = string.Empty;
|
private string _message = string.Empty;
|
||||||
private string _loadingDisplay = "display: none;";
|
private string _loadingDisplay = "display: none;";
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
// include CSS
|
// include CSS
|
||||||
var content = $"<link rel=\"stylesheet\" href=\"{Constants.BootstrapStylesheetUrl}\" integrity=\"{Constants.BootstrapStylesheetIntegrity}\" crossorigin=\"anonymous\" type=\"text/css\"/>";
|
var content = $"<link rel=\"stylesheet\" href=\"{Constants.BootstrapStylesheetUrl}\" integrity=\"{Constants.BootstrapStylesheetIntegrity}\" crossorigin=\"anonymous\" type=\"text/css\"/>";
|
||||||
SiteState.AppendHeadContent(content);
|
SiteState.AppendHeadContent(content);
|
||||||
|
|
||||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||||
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
|
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
|
||||||
|
|
||||||
_databases = await DatabaseService.GetDatabasesAsync();
|
_databases = await DatabaseService.GetDatabasesAsync();
|
||||||
if (_databases.Exists(item => item.IsDefault))
|
if (_databases.Exists(item => item.IsDefault))
|
||||||
{
|
{
|
||||||
_databaseName = _databases.Find(item => item.IsDefault).Name;
|
_databaseName = _databases.Find(item => item.IsDefault).Name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_databaseName = "LocalDB";
|
_databaseName = "LocalDB";
|
||||||
}
|
}
|
||||||
LoadDatabaseConfigComponent();
|
LoadDatabaseConfigComponent();
|
||||||
|
|
||||||
_templates = await SiteTemplateService.GetSiteTemplatesAsync();
|
_templates = await SiteTemplateService.GetSiteTemplatesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DatabaseChanged(ChangeEventArgs eventArgs)
|
private void DatabaseChanged(ChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_databaseName = (string)eventArgs.Value;
|
_databaseName = (string)eventArgs.Value;
|
||||||
_showConnectionString = false;
|
_showConnectionString = false;
|
||||||
LoadDatabaseConfigComponent();
|
LoadDatabaseConfigComponent();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
_message = Localizer["Error.DbConfig.Load"];
|
_message = Localizer["Error.DbConfig.Load"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadDatabaseConfigComponent()
|
private void LoadDatabaseConfigComponent()
|
||||||
{
|
{
|
||||||
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
|
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
|
||||||
if (database != null)
|
if (database != null)
|
||||||
{
|
{
|
||||||
_databaseConfigType = Type.GetType(database.ControlType);
|
_databaseConfigType = Type.GetType(database.ControlType);
|
||||||
DatabaseConfigComponent = builder =>
|
DatabaseConfigComponent = builder =>
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, _databaseConfigType);
|
builder.OpenComponent(0, _databaseConfigType);
|
||||||
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
|
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
// include JavaScript
|
// include JavaScript
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
await interop.IncludeScript("", Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous", "", "head");
|
await interop.IncludeScript("", Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous", "", "head");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Install()
|
private async Task Install()
|
||||||
{
|
{
|
||||||
var connectionString = String.Empty;
|
var connectionString = String.Empty;
|
||||||
if (_showConnectionString)
|
if (_showConnectionString)
|
||||||
{
|
{
|
||||||
connectionString = _connectionString;
|
connectionString = _connectionString;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
||||||
{
|
{
|
||||||
connectionString = databaseConfigControl.GetConnectionString();
|
connectionString = databaseConfigControl.GetConnectionString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@"))
|
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@") && !string.IsNullOrEmpty(_hostName))
|
||||||
{
|
{
|
||||||
if (await UserService.ValidatePasswordAsync(_hostPassword))
|
var result = await UserService.ValidateUserAsync(_hostUsername, _hostEmail, _hostPassword);
|
||||||
{
|
if (result.Succeeded)
|
||||||
_loadingDisplay = "";
|
{
|
||||||
StateHasChanged();
|
_loadingDisplay = "";
|
||||||
|
StateHasChanged();
|
||||||
|
|
||||||
Uri uri = new Uri(NavigationManager.Uri);
|
Uri uri = new Uri(NavigationManager.Uri);
|
||||||
|
|
||||||
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
|
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
|
||||||
|
|
||||||
var config = new InstallConfig
|
var config = new InstallConfig
|
||||||
{
|
{
|
||||||
DatabaseType = database.DBType,
|
DatabaseType = database.DBType,
|
||||||
ConnectionString = connectionString,
|
ConnectionString = connectionString,
|
||||||
Aliases = uri.Authority,
|
Aliases = uri.Authority,
|
||||||
HostUsername = _hostUsername,
|
HostUsername = _hostUsername,
|
||||||
HostPassword = _hostPassword,
|
HostPassword = _hostPassword,
|
||||||
HostEmail = _hostEmail,
|
HostEmail = _hostEmail,
|
||||||
HostName = _hostUsername,
|
HostName = _hostName,
|
||||||
TenantName = TenantNames.Master,
|
TenantName = TenantNames.Master,
|
||||||
IsNewTenant = true,
|
IsNewTenant = true,
|
||||||
SiteName = Constants.DefaultSite,
|
SiteName = Constants.DefaultSite,
|
||||||
Register = _register,
|
Register = _register,
|
||||||
SiteTemplate = _template,
|
SiteTemplate = _template,
|
||||||
RenderMode = RenderModes.Static,
|
RenderMode = RenderModes.Static,
|
||||||
Runtime = Runtimes.Server
|
Runtime = Runtimes.Server
|
||||||
};
|
};
|
||||||
|
|
||||||
var installation = await InstallationService.Install(config);
|
var installation = await InstallationService.Install(config);
|
||||||
if (installation.Success)
|
if (installation.Success)
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true);
|
NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_message = installation.Message;
|
_message = installation.Message;
|
||||||
_loadingDisplay = "display: none;";
|
_loadingDisplay = "display: none;";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_message = Localizer["Message.Password.Invalid"];
|
_message = string.Join("<br />", result.Errors.Select(i => !string.IsNullOrEmpty(i.Value) ? i.Value : Localizer[i.Key]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -15,22 +15,34 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="parent" HelpText="Select the parent folder" ResourceKey="Parent">Parent: </Label>
|
<Label Class="col-sm-3" For="parent" HelpText="Select the parent folder" ResourceKey="Parent">Parent: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="parent" class="form-select" @bind="@_parentId" required>
|
@if (_parentId == -1)
|
||||||
@if (PageState.QueryString.ContainsKey("id"))
|
{
|
||||||
{
|
<select id="parent" class="form-select" @bind="@_parentId" required>
|
||||||
<option value="-1"><@Localizer["NoParent"]></option>
|
<option value="-1"><@Localizer["NoParent"]></option>
|
||||||
}
|
</select>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<select id="parent" class="form-select" @bind="@_parentId" required>
|
||||||
@foreach (Folder folder in _folders)
|
@foreach (Folder folder in _folders)
|
||||||
{
|
{
|
||||||
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="name" HelpText="Enter the folder name" ResourceKey="Name">Name: </Label>
|
<Label Class="col-sm-3" For="name" HelpText="Enter the folder name" ResourceKey="Name">Name: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="name" class="form-control" @bind="@_name" maxlength="256" required />
|
@if (_isSystem)
|
||||||
|
{
|
||||||
|
<input id="name" class="form-control" @bind="@_name" readonly />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input id="name" class="form-control" @bind="@_name" maxlength="256" required />
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -49,18 +61,24 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="imagesizes" HelpText="Enter a list of image sizes which can be generated dynamically from uploaded images (ie. 200x200,400x400). Use * to indicate the folder supports all image sizes." ResourceKey="ImageSizes">Image Sizes: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="imagesizes" class="form-control" @bind="@_imagesizes" maxlength="512" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="capacity" HelpText="Enter the maximum folder capacity (in megabytes). Specify zero if the capacity is unlimited." ResourceKey="Capacity">Capacity: </Label>
|
<Label Class="col-sm-3" For="capacity" HelpText="Enter the maximum folder capacity (in megabytes). Specify zero if the capacity is unlimited." ResourceKey="Capacity">Capacity: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="capacity" class="form-control" @bind="@_capacity" required />
|
<input id="capacity" class="form-control" @bind="@_capacity" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="cachecontrol" HelpText="Optionally provide a Cache-Control directive for this folder. For example 'public, max-age=60' indicates that files in this folder should be cached for 60 seconds. Please note that when caching is enabled, changes to files will not be immediately reflected in the UI." ResourceKey="CacheControl">Caching: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="cachecontrol" class="form-control" @bind="@_cachecontrol" maxlength="50" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="imagesizes" HelpText="Optionally enter a list of image sizes which can be generated dynamically from uploaded images (ie. 200x200,400x400). Use * to indicate the folder supports all image sizes (not recommended)." ResourceKey="ImageSizes">Image Sizes: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="imagesizes" class="form-control" @bind="@_imagesizes" maxlength="512" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (PageState.QueryString.ContainsKey("id"))
|
@if (PageState.QueryString.ContainsKey("id"))
|
||||||
{
|
{
|
||||||
@ -100,8 +118,9 @@
|
|||||||
private int _parentId = -1;
|
private int _parentId = -1;
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _type = FolderTypes.Private;
|
private string _type = FolderTypes.Private;
|
||||||
private string _imagesizes = string.Empty;
|
|
||||||
private string _capacity = "0";
|
private string _capacity = "0";
|
||||||
|
private string _cachecontrol = string.Empty;
|
||||||
|
private string _imagesizes = string.Empty;
|
||||||
private bool _isSystem;
|
private bool _isSystem;
|
||||||
private List<Permission> _permissions = null;
|
private List<Permission> _permissions = null;
|
||||||
private string _createdBy;
|
private string _createdBy;
|
||||||
@ -132,8 +151,9 @@
|
|||||||
_parentId = folder.ParentId ?? -1;
|
_parentId = folder.ParentId ?? -1;
|
||||||
_name = folder.Name;
|
_name = folder.Name;
|
||||||
_type = folder.Type;
|
_type = folder.Type;
|
||||||
_imagesizes = folder.ImageSizes;
|
|
||||||
_capacity = folder.Capacity.ToString();
|
_capacity = folder.Capacity.ToString();
|
||||||
|
_cachecontrol = folder.CacheControl;
|
||||||
|
_imagesizes = folder.ImageSizes;
|
||||||
_isSystem = folder.IsSystem;
|
_isSystem = folder.IsSystem;
|
||||||
_permissions = folder.PermissionList;
|
_permissions = folder.PermissionList;
|
||||||
_createdBy = folder.CreatedBy;
|
_createdBy = folder.CreatedBy;
|
||||||
@ -204,8 +224,9 @@
|
|||||||
folder.SiteId = PageState.Site.SiteId;
|
folder.SiteId = PageState.Site.SiteId;
|
||||||
folder.Name = _name;
|
folder.Name = _name;
|
||||||
folder.Type = _type;
|
folder.Type = _type;
|
||||||
folder.ImageSizes = _imagesizes;
|
|
||||||
folder.Capacity = int.Parse(_capacity);
|
folder.Capacity = int.Parse(_capacity);
|
||||||
|
folder.CacheControl = _cachecontrol;
|
||||||
|
folder.ImageSizes = _imagesizes;
|
||||||
folder.IsSystem = _isSystem;
|
folder.IsSystem = _isSystem;
|
||||||
folder.PermissionList = _permissionGrid.GetPermissionList();
|
folder.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
|
|
||||||
@ -220,7 +241,6 @@
|
|||||||
|
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
{
|
{
|
||||||
await FolderService.UpdateFolderOrderAsync(folder.SiteId, folder.FolderId, folder.ParentId);
|
|
||||||
await logger.LogInformation("Folder Saved {Folder}", folder);
|
await logger.LogInformation("Folder Saved {Folder}", folder);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
@ -256,17 +276,9 @@
|
|||||||
}
|
}
|
||||||
if (!isparent)
|
if (!isparent)
|
||||||
{
|
{
|
||||||
var files = await FileService.GetFilesAsync(_folderId);
|
await FolderService.DeleteFolderAsync(_folderId);
|
||||||
if (files.Count == 0)
|
await logger.LogInformation("Folder Deleted {Folder}", _folderId);
|
||||||
{
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
await FolderService.DeleteFolderAsync(_folderId);
|
|
||||||
await logger.LogInformation("Folder Deleted {Folder}", _folderId);
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.Folder.Files.InvalidDelete"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3,54 +3,92 @@
|
|||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IFolderService FolderService
|
@inject IFolderService FolderService
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
|
@inject ISettingService SettingService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@if (_files != null)
|
@if (_files == null)
|
||||||
{
|
{
|
||||||
<div class="row">
|
<p>
|
||||||
<div class="col-md mb-1">
|
<em>@SharedLocalizer["Loading"]</em>
|
||||||
<ActionLink Action="Edit" Text="Add Folder" Class="btn btn-secondary" ResourceKey="AddFolder" />
|
</p>
|
||||||
</div>
|
}
|
||||||
<div class="col-md-8 mb-1">
|
else
|
||||||
<div class="input-group">
|
{
|
||||||
<span class="input-group-text">@Localizer["Folder"]:</span>
|
<TabStrip>
|
||||||
<select class="form-select" @onchange="(e => FolderChanged(e))">
|
<TabPanel Name="Files" Heading="Files" ResourceKey="Files">
|
||||||
@foreach (Folder folder in _folders)
|
<div class="row">
|
||||||
{
|
<div class="col-md mb-1">
|
||||||
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
<ActionLink Action="Edit" Text="Add Folder" Class="btn btn-secondary" ResourceKey="AddFolder" />
|
||||||
}
|
</div>
|
||||||
</select>
|
<div class="col-md-8 mb-1">
|
||||||
<ActionLink Action="Edit" Text="Edit Folder" Class="btn btn-secondary" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="EditFolder" />
|
<div class="input-group">
|
||||||
|
<span class="input-group-text">@Localizer["Folder"]:</span>
|
||||||
|
<select class="form-select" @onchange="(e => FolderChanged(e))">
|
||||||
|
@foreach (Folder folder in _folders)
|
||||||
|
{
|
||||||
|
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<ActionLink Action="Edit" Text="Edit Folder" Class="btn btn-secondary" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="EditFolder" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md mb-1 text-end">
|
||||||
|
<ActionLink Action="Add" Text="Upload Files" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="UploadFiles" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col-md mb-1 text-end">
|
|
||||||
<ActionLink Action="Add" Text="Upload Files" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="UploadFiles" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Pager Items="@_files" SearchProperties="Name">
|
@if (_files.Count != 0)
|
||||||
<Header>
|
{
|
||||||
<th style="width: 1px;"> </th>
|
<Pager Items="@_files" SearchProperties="Name">
|
||||||
<th style="width: 1px;"> </th>
|
<Header>
|
||||||
<th>@SharedLocalizer["Name"]</th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@Localizer["Modified"]</th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@Localizer["Type"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
<th>@Localizer["Size"]</th>
|
<th>@Localizer["Modified"]</th>
|
||||||
</Header>
|
<th>@Localizer["Type"]</th>
|
||||||
<Row>
|
<th>@Localizer["Size"]</th>
|
||||||
<td><ActionLink Action="Details" Text="Edit" Parameters="@($"id=" + context.FileId.ToString())" ResourceKey="Details" /></td>
|
</Header>
|
||||||
<td><ActionDialog Header="Delete File" Message="@string.Format(Localizer["Confirm.File.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFile(context))" ResourceKey="DeleteFile" /></td>
|
<Row>
|
||||||
<td><a href="@context.Url" target="_new">@context.Name</a></td>
|
<td><ActionLink Action="Details" Text="Edit" Parameters="@($"id=" + context.FileId.ToString())" ResourceKey="Details" /></td>
|
||||||
<td>@context.ModifiedOn</td>
|
<td><ActionDialog Header="Delete File" Message="@string.Format(Localizer["Confirm.File.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFile(context))" ResourceKey="DeleteFile" /></td>
|
||||||
<td>@context.Extension.ToUpper() @SharedLocalizer["File"]</td>
|
<td><a href="@context.Url" target="_new">@context.Name</a></td>
|
||||||
<td>@string.Format("{0:0.00}", ((decimal)context.Size / 1000)) KB</td>
|
<td>@UtcToLocal(context.ModifiedOn)</td>
|
||||||
</Row>
|
<td>@context.Extension.ToUpper() @SharedLocalizer["File"]</td>
|
||||||
</Pager>
|
<td>@string.Format("{0:0.00}", ((decimal)context.Size / 1000)) KB</td>
|
||||||
@if (_files.Count == 0)
|
</Row>
|
||||||
{
|
</Pager>
|
||||||
<div class="text-center">@Localizer["NoFiles"]</div>
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
<div class="text-center">@Localizer["NoFiles"]</div>
|
||||||
|
}
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings" Security="SecurityAccessLevel.Admin">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="imageExt" HelpText="Enter a comma separated list of image file extensions" ResourceKey="ImageExtensions">Image Extensions: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="imageExt" spellcheck="false" class="form-control" @bind="@_imageFiles" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="uploadableFileExt" HelpText="Enter a comma separated list of uploadable file extensions" ResourceKey="UploadableFileExtensions">Uploadable File Extensions: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="uploadableFileExt" spellcheck="false" class="form-control" @bind="@_uploadableFiles" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="maxChunkSize" HelpText="Files are split into chunks to streamline the upload process. Specify the maximum chunk size in MB (note that higher chunk sizes should only be used on faster networks)." ResourceKey="MaxChunkSize">Max Upload Chunk Size (MB): </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="maxChunkSize" type="number" min="1" max="10" step="1" class="form-control" @bind="@_maxChunkSize" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||||
|
</TabPanel>
|
||||||
|
</TabStrip>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
@ -58,6 +96,10 @@
|
|||||||
private int _folderId = -1;
|
private int _folderId = -1;
|
||||||
private List<File> _files;
|
private List<File> _files;
|
||||||
|
|
||||||
|
private string _imageFiles = string.Empty;
|
||||||
|
private string _uploadableFiles = string.Empty;
|
||||||
|
private int _maxChunkSize = 1;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
@ -71,6 +113,13 @@
|
|||||||
_folderId = _folders[0].FolderId;
|
_folderId = _folders[0].FolderId;
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
_imageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles);
|
||||||
|
_imageFiles = (string.IsNullOrEmpty(_imageFiles)) ? Constants.ImageFiles : _imageFiles;
|
||||||
|
_uploadableFiles = SettingService.GetSetting(settings, "UploadableFiles", Constants.UploadableFiles);
|
||||||
|
_uploadableFiles = (string.IsNullOrEmpty(_uploadableFiles)) ? Constants.UploadableFiles : _uploadableFiles;
|
||||||
|
_maxChunkSize = int.Parse(SettingService.GetSetting(settings, "MaxChunkSize", "1"));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -115,4 +164,23 @@
|
|||||||
AddModuleMessage(string.Format(Localizer["Error.File.Delete"], file.Name), MessageType.Error);
|
AddModuleMessage(string.Format(Localizer["Error.File.Delete"], file.Name), MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task SaveSiteSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
settings = SettingService.SetSetting(settings, "ImageFiles", (_imageFiles != Constants.ImageFiles) ? _imageFiles.Replace(" ", "") : "", false);
|
||||||
|
settings = SettingService.SetSetting(settings, "UploadableFiles", (_uploadableFiles != Constants.UploadableFiles) ? _uploadableFiles.Replace(" ", "") : "", false);
|
||||||
|
settings = SettingService.SetSetting(settings, "MaxChunkSize", _maxChunkSize.ToString(), false);
|
||||||
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
|
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="retention" HelpText="Number of log entries to retain for this job" ResourceKey="RetentionLog">Retention Log (Items): </Label>
|
<Label Class="col-sm-3" For="retention" HelpText="Number of log entries to retain for this job" ResourceKey="RetentionLog">Retention Log (Items): </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="retention" type="number" min="0" step ="1" class="form-control" @bind="@_retentionHistory" maxlength="4" required />
|
<input id="retention" type="number" min="0" step ="1" class="form-control" @bind="@_retentionHistory" maxlength="3" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -132,13 +132,13 @@
|
|||||||
_isEnabled = job.IsEnabled.ToString();
|
_isEnabled = job.IsEnabled.ToString();
|
||||||
_interval = job.Interval.ToString();
|
_interval = job.Interval.ToString();
|
||||||
_frequency = job.Frequency;
|
_frequency = job.Frequency;
|
||||||
_startDate = Utilities.UtcAsLocalDate(job.StartDate);
|
_startDate = UtcToLocal(job.StartDate);
|
||||||
_startTime = Utilities.UtcAsLocalDateTime(job.StartDate);
|
_startTime = UtcToLocal(job.StartDate);
|
||||||
_endDate = Utilities.UtcAsLocalDate(job.EndDate);
|
_endDate = UtcToLocal(job.EndDate);
|
||||||
_endTime = Utilities.UtcAsLocalDateTime(job.EndDate);
|
_endTime = UtcToLocal(job.EndDate);
|
||||||
_retentionHistory = job.RetentionHistory.ToString();
|
_retentionHistory = job.RetentionHistory.ToString();
|
||||||
_nextDate = Utilities.UtcAsLocalDate(job.NextExecution);
|
_nextDate = UtcToLocal(job.NextExecution);
|
||||||
_nextTime = Utilities.UtcAsLocalDateTime(job.NextExecution);
|
_nextTime = UtcToLocal(job.NextExecution);
|
||||||
createdby = job.CreatedBy;
|
createdby = job.CreatedBy;
|
||||||
createdon = job.CreatedOn;
|
createdon = job.CreatedOn;
|
||||||
modifiedby = job.ModifiedBy;
|
modifiedby = job.ModifiedBy;
|
||||||
@ -176,10 +176,10 @@
|
|||||||
{
|
{
|
||||||
job.Interval = int.Parse(_interval);
|
job.Interval = int.Parse(_interval);
|
||||||
}
|
}
|
||||||
job.StartDate = Utilities.LocalDateAndTimeAsUtc(_startDate, _startTime);
|
job.StartDate = LocalToUtc(_startDate.Value.Date.Add(_startTime.Value.TimeOfDay));
|
||||||
job.EndDate = Utilities.LocalDateAndTimeAsUtc(_endDate, _endTime);
|
job.EndDate = LocalToUtc(_endDate.Value.Date.Add(_endTime.Value.TimeOfDay));
|
||||||
job.RetentionHistory = int.Parse(_retentionHistory);
|
job.RetentionHistory = int.Parse(_retentionHistory);
|
||||||
job.NextExecution = Utilities.LocalDateAndTimeAsUtc(_nextDate, _nextTime);
|
job.NextExecution = LocalToUtc(_nextDate.Value.Date.Add(_nextTime.Value.TimeOfDay));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -29,7 +29,7 @@ else
|
|||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@DisplayStatus(context.IsEnabled, context.IsExecuting)</td>
|
<td>@DisplayStatus(context.IsEnabled, context.IsExecuting)</td>
|
||||||
<td>@DisplayFrequency(context.Interval, context.Frequency)</td>
|
<td>@DisplayFrequency(context.Interval, context.Frequency)</td>
|
||||||
<td>@context.NextExecution?.ToLocalTime()</td>
|
<td>@UtcToLocal(context.NextExecution)</td>
|
||||||
<td>
|
<td>
|
||||||
@if (context.IsStarted)
|
@if (context.IsStarted)
|
||||||
{
|
{
|
||||||
@ -55,10 +55,6 @@ else
|
|||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await GetJobs();
|
await GetJobs();
|
||||||
if (_jobs.Count == 0)
|
|
||||||
{
|
|
||||||
AddModuleMessage(string.Format(Localizer["Message.NoJobs"], NavigateUrl("admin/system")), MessageType.Warning);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetJobs()
|
private async Task GetJobs()
|
||||||
|
@ -23,8 +23,8 @@ else
|
|||||||
<Row>
|
<Row>
|
||||||
<td>@context.Job.Name</td>
|
<td>@context.Job.Name</td>
|
||||||
<td>@DisplayStatus(context.Job.IsExecuting, context.Succeeded)</td>
|
<td>@DisplayStatus(context.Job.IsExecuting, context.Succeeded)</td>
|
||||||
<td>@context.StartDate</td>
|
<td>@UtcToLocal(context.StartDate)</td>
|
||||||
<td>@context.FinishDate</td>
|
<td>@UtcToLocal(context.FinishDate)</td>
|
||||||
</Row>
|
</Row>
|
||||||
<Detail>
|
<Detail>
|
||||||
<td colspan="4">@((MarkupString)context.Notes)</td>
|
<td colspan="4">@((MarkupString)context.Notes)</td>
|
||||||
@ -44,14 +44,12 @@ else
|
|||||||
|
|
||||||
private async Task GetJobLogs()
|
private async Task GetJobLogs()
|
||||||
{
|
{
|
||||||
_jobLogs = await JobLogService.GetJobLogsAsync();
|
var jobId = -1;
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("id"))
|
if (PageState.QueryString.ContainsKey("id"))
|
||||||
{
|
{
|
||||||
_jobLogs = _jobLogs.Where(item => item.JobId == Int32.Parse(PageState.QueryString["id"])).ToList();
|
jobId = int.Parse(PageState.QueryString["id"]);
|
||||||
}
|
}
|
||||||
|
_jobLogs = await JobLogService.GetJobLogsAsync(jobId);
|
||||||
_jobLogs = _jobLogs.OrderByDescending(item => item.JobLogId).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string DisplayStatus(bool isExecuting, bool? succeeded)
|
private string DisplayStatus(bool isExecuting, bool? succeeded)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
@namespace Oqtane.Modules.Admin.Languages
|
@namespace Oqtane.Modules.Admin.Languages
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@using System.Globalization
|
@using System.Globalization
|
||||||
@using Microsoft.AspNetCore.Localization
|
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject ILocalizationService LocalizationService
|
@inject ILocalizationService LocalizationService
|
||||||
@inject ILanguageService LanguageService
|
@inject ILanguageService LanguageService
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
@namespace Oqtane.Modules.Admin.Languages
|
@namespace Oqtane.Modules.Admin.Languages
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@using System.Globalization
|
@using System.Globalization
|
||||||
@using Microsoft.AspNetCore.Localization
|
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject ILocalizationService LocalizationService
|
@inject ILocalizationService LocalizationService
|
||||||
@inject ILanguageService LanguageService
|
@inject ILanguageService LanguageService
|
||||||
|
@ -29,12 +29,12 @@ else
|
|||||||
{
|
{
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<Label Class="control-label" For="username" HelpText="Please enter your Username" ResourceKey="Username">Username:</Label>
|
<Label Class="control-label" For="username" HelpText="Please enter your Username" ResourceKey="Username">Username:</Label>
|
||||||
<input id="username" type="text" @ref="username" class="form-control" placeholder="@Localizer["Username.Placeholder"]" @bind="@_username" required />
|
<input id="username" type="text" @ref="username" class="form-control" placeholder="@Localizer["Username.Placeholder"]" @bind="@_username" @bind:event="oninput" required />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group mt-2">
|
<div class="form-group mt-2">
|
||||||
<Label Class="control-label" For="password" HelpText="Please enter your Password" ResourceKey="Password">Password:</Label>
|
<Label Class="control-label" For="password" HelpText="Please enter your Password" ResourceKey="Password">Password:</Label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordtype" name="Password" class="form-control" placeholder="@Localizer["Password.Placeholder"]" @bind="@_password" required />
|
<input id="password" type="@_passwordtype" name="Password" class="form-control" placeholder="@Localizer["Password.Placeholder"]" @bind="@_password" @bind:event="oninput" required />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -144,7 +144,7 @@ else
|
|||||||
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
|
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
await logger.LogInformation(LogFunction.Security, "Email Verified For For Username {Username}", _username);
|
await logger.LogInformation(LogFunction.Security, "Email Verified For Username {Username}", _username);
|
||||||
AddModuleMessage(Localizer["Success.Account.Verified"], MessageType.Info);
|
AddModuleMessage(Localizer["Success.Account.Verified"], MessageType.Info);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -141,7 +141,7 @@
|
|||||||
var log = await LogService.GetLogAsync(_logId);
|
var log = await LogService.GetLogAsync(_logId);
|
||||||
if (log != null)
|
if (log != null)
|
||||||
{
|
{
|
||||||
_logDate = log.LogDate.ToString(CultureInfo.CurrentCulture);
|
_logDate = UtcToLocal(log.LogDate).Value.ToString(CultureInfo.CurrentCulture);
|
||||||
_level = log.Level;
|
_level = log.Level;
|
||||||
_feature = log.Feature;
|
_feature = log.Feature;
|
||||||
_function = log.Function;
|
_function = log.Function;
|
||||||
|
@ -64,7 +64,7 @@ else
|
|||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Text="Details" Parameters="@($"/{context.LogId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_level, _function, _rows, _page)))" ResourceKey="LogDetails" /></td>
|
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Text="Details" Parameters="@($"/{context.LogId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_level, _function, _rows, _page)))" ResourceKey="LogDetails" /></td>
|
||||||
<td class="@GetClass(context.Function)">@context.LogDate</td>
|
<td class="@GetClass(context.Function)">@UtcToLocal(context.LogDate)</td>
|
||||||
<td class="@GetClass(context.Function)">@context.Level</td>
|
<td class="@GetClass(context.Function)">@context.Level</td>
|
||||||
<td class="@GetClass(context.Function)">@context.Feature</td>
|
<td class="@GetClass(context.Function)">@context.Feature</td>
|
||||||
<td class="@GetClass(context.Function)">@context.Function</td>
|
<td class="@GetClass(context.Function)">@context.Function</td>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="description" HelpText="Enter a short description for the module" ResourceKey="Description">Description: </Label>
|
<Label Class="col-sm-3" For="description" HelpText="Enter a short description for the module" ResourceKey="Description">Description: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="description" class="form-control" @bind="@_description" rows="3" maxlength="2000" required></textarea>
|
<textarea id="description" class="form-control" @bind="@_description" rows="3" maxlength="2000"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -111,6 +111,8 @@
|
|||||||
private async Task CreateModule()
|
private async Task CreateModule()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
|
_owner = _owner.Trim();
|
||||||
|
_module = _module.Trim();
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
if (await interop.FormValid(form))
|
if (await interop.FormValid(form))
|
||||||
{
|
{
|
||||||
@ -118,6 +120,7 @@
|
|||||||
{
|
{
|
||||||
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
|
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(_description)) _description = _module;
|
||||||
if (IsValidXML(_description))
|
if (IsValidXML(_description))
|
||||||
{
|
{
|
||||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
@namespace Oqtane.Modules.Admin.ModuleDefinitions
|
@namespace Oqtane.Modules.Admin.ModuleDefinitions
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@using System.Globalization
|
@using System.Globalization
|
||||||
@using Microsoft.AspNetCore.Localization
|
|
||||||
@inject IModuleDefinitionService ModuleDefinitionService
|
@inject IModuleDefinitionService ModuleDefinitionService
|
||||||
@inject IPackageService PackageService
|
@inject IPackageService PackageService
|
||||||
@inject ILanguageService LanguageService
|
@inject ILanguageService LanguageService
|
||||||
@ -64,24 +63,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed. This value must be specified within the module's IModule interface specification." ResourceKey="PackageName">Package Name: </Label>
|
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed. This value must be specified within the module's IModule interface specification." ResourceKey="PackageName">Package Name: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@if (!string.IsNullOrEmpty(_packagename))
|
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||||
{
|
|
||||||
<div class="input-group">
|
|
||||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
|
||||||
@if (string.IsNullOrEmpty(_packageurl))
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="ValidatePackage">@Localizer["Validate"]</button>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<a href="@_packageurl" target="_blank" class="btn btn-primary">@SharedLocalizer["Download"]</a>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -91,7 +73,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="url" HelpText="The reference url of the module" ResourceKey="ReferenceUrl">Reference Url: </Label>
|
<Label Class="col-sm-3" For="url" HelpText="The url of the module" ResourceKey="Url">Url: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="url" class="form-control" @bind="@_url" disabled />
|
<input id="url" class="form-control" @bind="@_url" disabled />
|
||||||
</div>
|
</div>
|
||||||
@ -245,7 +227,6 @@
|
|||||||
private string _moduledefinitionname = "";
|
private string _moduledefinitionname = "";
|
||||||
private string _version;
|
private string _version;
|
||||||
private string _packagename = "";
|
private string _packagename = "";
|
||||||
private string _packageurl = "";
|
|
||||||
private string _owner = "";
|
private string _owner = "";
|
||||||
private string _url = "";
|
private string _url = "";
|
||||||
private string _contact = "";
|
private string _contact = "";
|
||||||
@ -446,27 +427,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ValidatePackage()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var package = await PackageService.GetPackageAsync(_packagename, _version, true);
|
|
||||||
if (package == null || string.IsNullOrEmpty(package.PackageUrl))
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.Validate"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_packageurl = package.PackageUrl;
|
|
||||||
AddModuleMessage(Localizer["Message.Download"], MessageType.Info);
|
|
||||||
}
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packagename, _version);
|
|
||||||
AddModuleMessage(Localizer["Error.Validate"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private string Browse(Page page) => string.IsNullOrEmpty(page.Url) ? NavigateUrl(page.Path) : page.Url;
|
private string Browse(Page page) => string.IsNullOrEmpty(page.Url) ? NavigateUrl(page.Path) : page.Url;
|
||||||
}
|
}
|
||||||
|
@ -13,32 +13,32 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-3 align-items-center">
|
<div class="row mb-3 align-items-center">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<ActionLink Action="Add" Text="Install Module" ResourceKey="InstallModule" />
|
<ActionLink Action="Add" Text="Install Module" ResourceKey="InstallModule" />
|
||||||
@((MarkupString)" ")
|
<ActionLink Action="Create" Text="Create Module" ResourceKey="CreateModule" Class="btn btn-secondary ps-2" />
|
||||||
<ActionLink Action="Create" Text="Create Module" ResourceKey="CreateModule" Class="btn btn-secondary" />
|
<button type="button" class="btn btn-secondary pw-2" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
||||||
@foreach (var category in _categories)
|
@foreach (var category in _categories)
|
||||||
{
|
{
|
||||||
if (category == _category)
|
if (category == _category)
|
||||||
{
|
{
|
||||||
<option value="@category" selected>@category @Localizer["Modules"]</option>
|
<option value="@category" selected>@category @Localizer["Modules"]</option>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<option value="@category">@category @Localizer["Modules"]</option>
|
<option value="@category">@category @Localizer["Modules"]</option>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Pager Items="@_moduleDefinitions">
|
<Pager Items="@_moduleDefinitions">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
@ -61,17 +61,17 @@ else
|
|||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@context.Version</td>
|
<td>@context.Version</td>
|
||||||
<td>
|
<td>
|
||||||
@if (context.IsEnabled)
|
@if (context.IsEnabled)
|
||||||
{
|
{
|
||||||
<span>@SharedLocalizer["Yes"]</span>
|
<span>@SharedLocalizer["Yes"]</span>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<span>@SharedLocalizer["No"]</span>
|
<span>@SharedLocalizer["No"]</span>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if (context.AssemblyName == Constants.ClientId || _modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
|
@if (context.AssemblyName == Constants.ClientId || _modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
|
||||||
{
|
{
|
||||||
<span>@SharedLocalizer["Yes"]</span>
|
<span>@SharedLocalizer["Yes"]</span>
|
||||||
}
|
}
|
||||||
@ -87,9 +87,9 @@ else
|
|||||||
@((MarkupString)PurchaseLink(context.PackageName))
|
@((MarkupString)PurchaseLink(context.PackageName))
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@{
|
@{
|
||||||
var version = UpgradeAvailable(context.PackageName, context.Version);
|
var version = UpgradeAvailable(context.PackageName, context.Version);
|
||||||
}
|
}
|
||||||
@if (version != context.Version)
|
@if (version != context.Version)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadModule(context.PackageName, version))>@SharedLocalizer["Upgrade"]</button>
|
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadModule(context.PackageName, version))>@SharedLocalizer["Upgrade"]</button>
|
||||||
@ -153,10 +153,10 @@ else
|
|||||||
link = "<a class=\"btn btn-primary\" style=\"text-decoration: none !important\" href=\"" + package.PaymentUrl + "\" target=\"_new\">" + package.ExpiryDate.Value.Date.ToString("MMM dd, yyyy") + "</a>";
|
link = "<a class=\"btn btn-primary\" style=\"text-decoration: none !important\" href=\"" + package.PaymentUrl + "\" target=\"_new\">" + package.ExpiryDate.Value.Date.ToString("MMM dd, yyyy") + "</a>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SupportLink(string packagename, string version)
|
private string SupportLink(string packagename, string version)
|
||||||
{
|
{
|
||||||
@ -172,52 +172,75 @@ else
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string UpgradeAvailable(string packagename, string version)
|
private string UpgradeAvailable(string packagename, string version)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||||
{
|
{
|
||||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||||
if (package != null && Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
if (package != null && Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
||||||
{
|
{
|
||||||
return package.Version;
|
return package.Version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadModule(string packagename, string version)
|
private async Task DownloadModule(string packagename, string version)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(packagename, version);
|
await PackageService.DownloadPackageAsync(packagename, version);
|
||||||
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version} {Error}", packagename, version, ex.Message);
|
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version} {Error}", packagename, version, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteModule(ModuleDefinition moduleDefinition)
|
private async Task DeleteModule(ModuleDefinition moduleDefinition)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ModuleDefinitionService.DeleteModuleDefinitionAsync(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId);
|
await ModuleDefinitionService.DeleteModuleDefinitionAsync(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId);
|
||||||
AddModuleMessage(Localizer["Success.Module.Delete"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.Module.Delete"], MessageType.Success);
|
||||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true));
|
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Deleting Module {ModuleDefinition} {Error}", moduleDefinition, ex.Message);
|
await logger.LogError(ex, "Error Deleting Module {ModuleDefinition} {Error}", moduleDefinition, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CategoryChanged(ChangeEventArgs e)
|
private async Task CategoryChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_category = (string)e.Value;
|
_category = (string)e.Value;
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task Synchronize()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ShowProgressIndicator();
|
||||||
|
foreach (var moduleDefinition in _moduleDefinitions)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(moduleDefinition.PackageName) && !_packages.Any(item => item.PackageId == moduleDefinition.PackageName))
|
||||||
|
{
|
||||||
|
var package = await PackageService.GetPackageAsync(moduleDefinition.PackageName, moduleDefinition.Version, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HideProgressIndicator();
|
||||||
|
AddModuleMessage(Localizer["Success.Module.Synchronize"], MessageType.Success);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Synchronizing Modules {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Module.Synchronize"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,24 +5,57 @@
|
|||||||
@inject IStringLocalizer<Export> Localizer
|
@inject IStringLocalizer<Export> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<div class="container">
|
<TabStrip>
|
||||||
<div class="row mb-1 align-items-center">
|
<TabPanel Name="Content" Heading="Content" ResourceKey="Content">
|
||||||
<Label Class="col-sm-3" For="content" HelpText="The Exported Module Content" ResourceKey="Content">Content: </Label>
|
<div class="container">
|
||||||
<div class="col-sm-9">
|
<div class="row mb-1 align-items-center">
|
||||||
<textarea id="content" class="form-control" @bind="@_content" rows="5" readonly></textarea>
|
<Label Class="col-sm-3" For="content" HelpText="Select the Export option and you will be able to view the module content" ResourceKey="Content">Content: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="content" class="form-control" @bind="@_content" rows="5" readonly></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<br />
|
||||||
</div>
|
<button type="button" class="btn btn-success" @onclick="ExportText">@Localizer["Export"]</button>
|
||||||
|
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel Name="File" Heading="File" ResourceKey="File">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="folder" HelpText="Select a folder where you wish to save the exported content" ResourceKey="Folder">Folder: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<FileManager ShowFiles="false" ShowUpload="false" @ref="_filemanager" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="filename" HelpText="Specify a name for the file (without an extension)" ResourceKey="Filename">Filename: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="content" type="text" class="form-control" @bind="@_filename" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="ExportFile">@Localizer["Export"]</button>
|
||||||
|
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
</TabPanel>
|
||||||
|
</TabStrip>
|
||||||
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-success" @onclick="ExportModule">@Localizer["Export"]</button>
|
|
||||||
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string _content = string.Empty;
|
private string _content = string.Empty;
|
||||||
|
private FileManager _filemanager;
|
||||||
|
private string _filename = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
public override string Title => "Export Content";
|
public override string Title => "Export Content";
|
||||||
|
|
||||||
private async Task ExportModule()
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
_filename = Utilities.GetFriendlyUrl(ModuleState.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExportText()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -35,4 +68,34 @@
|
|||||||
AddModuleMessage(Localizer["Error.Module.Export"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Export"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ExportFile()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var folderid = _filemanager.GetFolderId();
|
||||||
|
if (folderid != -1 && !string.IsNullOrEmpty(_filename))
|
||||||
|
{
|
||||||
|
var fileid = await ModuleService.ExportModuleAsync(ModuleState.ModuleId, PageState.Page.PageId, folderid, _filename);
|
||||||
|
if (fileid != -1)
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Success.Content.Export"], MessageType.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Error.Module.Export"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Content.Export"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Exporting Module {ModuleId} {Error}", ModuleState.ModuleId, ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Module.Export"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,27 @@
|
|||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IModuleService ModuleService
|
@inject IModuleService ModuleService
|
||||||
|
@inject IFileService FileService
|
||||||
@inject IStringLocalizer<Import> Localizer
|
@inject IStringLocalizer<Import> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="content" HelpText="Enter The Module Content To Import" ResourceKey="Content">Content: </Label>
|
<Label Class="col-sm-3" For="file" HelpText="Optionally upload or select a file to import for this module" ResourceKey="File">File: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<FileManager Filter="json" OnSelectFile="OnSelectFile" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="content" HelpText="Provide the module content to import" ResourceKey="Content">Content: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="content" class="form-control" @bind="@_content" rows="5" required></textarea>
|
<textarea id="content" class="form-control" @bind="@_content" rows="5" required></textarea>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="ImportModule">@Localizer["Import"]</button>
|
<button type="button" class="btn btn-success" @onclick="ImportModule">@Localizer["Import"]</button>
|
||||||
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
</form>
|
</form>
|
||||||
@ -28,6 +35,12 @@
|
|||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
public override string Title => "Import Content";
|
public override string Title => "Import Content";
|
||||||
|
|
||||||
|
private async Task OnSelectFile(int fileId)
|
||||||
|
{
|
||||||
|
var bytes = await FileService.DownloadFileAsync(fileId);
|
||||||
|
_content = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ImportModule()
|
private async Task ImportModule()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
@if (_initialized)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<TabStrip>
|
<TabStrip ActiveTab="@_activetab">
|
||||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||||
@if (_containers != null)
|
@if (_containers != null)
|
||||||
{
|
{
|
||||||
@ -97,6 +97,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br />
|
||||||
|
<Section Name="ModuleContent" Heading="Content" ResourceKey="ModuleContent">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="moduleheader" HelpText="Optionally provide content to be injected above the module instance" ResourceKey="Header">Header: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="moduleheader" class="form-control" @bind="@_header" rows="3" maxlength="4000"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="modulefooter" HelpText="Optionally provide content to be injected below the module instance" ResourceKey="Footer">Footer: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="modulefooter" class="form-control" @bind="@_footer" rows="3" maxlength="4000"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Permissions" Heading="Permissions" ResourceKey="Permissions">
|
<TabPanel Name="Permissions" Heading="Permissions" ResourceKey="Permissions">
|
||||||
@ -144,6 +161,8 @@
|
|||||||
private string _pane;
|
private string _pane;
|
||||||
private string _containerType;
|
private string _containerType;
|
||||||
private string _allPages = "false";
|
private string _allPages = "false";
|
||||||
|
private string _header = "";
|
||||||
|
private string _footer = "";
|
||||||
private string _permissionNames = "";
|
private string _permissionNames = "";
|
||||||
private List<Permission> _permissions = null;
|
private List<Permission> _permissions = null;
|
||||||
private string _pageId;
|
private string _pageId;
|
||||||
@ -162,41 +181,52 @@
|
|||||||
private DateTime? _effectivedate = null;
|
private DateTime? _effectivedate = null;
|
||||||
private DateTime? _expirydate = null;
|
private DateTime? _expirydate = null;
|
||||||
private List<Page> _pages;
|
private List<Page> _pages;
|
||||||
|
private string _activetab = "";
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
SetModuleTitle(Localizer["ModuleSettings.Title"]);
|
SetModuleTitle(Localizer["ModuleSettings.Title"]);
|
||||||
|
|
||||||
_title = ModuleState.Title;
|
|
||||||
_moduleSettingsTitle = Localizer["ModuleSettings.Heading"];
|
_moduleSettingsTitle = Localizer["ModuleSettings.Heading"];
|
||||||
_pane = ModuleState.Pane;
|
|
||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
||||||
_containerType = ModuleState.ContainerType;
|
|
||||||
_allPages = ModuleState.AllPages.ToString();
|
|
||||||
_permissions = ModuleState.PermissionList;
|
|
||||||
_pageId = ModuleState.PageId.ToString();
|
|
||||||
createdby = ModuleState.CreatedBy;
|
|
||||||
createdon = ModuleState.CreatedOn;
|
|
||||||
modifiedby = ModuleState.ModifiedBy;
|
|
||||||
modifiedon = ModuleState.ModifiedOn;
|
|
||||||
_effectivedate = Utilities.UtcAsLocalDate(ModuleState.EffectiveDate);
|
|
||||||
_expirydate = Utilities.UtcAsLocalDate(ModuleState.ExpiryDate);
|
|
||||||
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
if (ModuleState.ModuleDefinition != null)
|
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
||||||
{
|
|
||||||
_module = ModuleState.ModuleDefinition.Name;
|
|
||||||
_permissionNames = ModuleState.ModuleDefinition?.PermissionNames;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
|
_pageId = pagemodule.PageId.ToString();
|
||||||
|
_title = pagemodule.Title;
|
||||||
|
_pane = pagemodule.Pane;
|
||||||
|
_containerType = pagemodule.ContainerType;
|
||||||
|
if (string.IsNullOrEmpty(_containerType))
|
||||||
|
{
|
||||||
|
_containerType = (!string.IsNullOrEmpty(PageState.Page.DefaultContainerType)) ? PageState.Page.DefaultContainerType : PageState.Site.DefaultContainerType;
|
||||||
|
}
|
||||||
|
_header = pagemodule.Header;
|
||||||
|
_footer = pagemodule.Footer;
|
||||||
|
_effectivedate = Utilities.UtcAsLocalDate(pagemodule.EffectiveDate);
|
||||||
|
_expirydate = Utilities.UtcAsLocalDate(pagemodule.ExpiryDate);
|
||||||
|
|
||||||
|
_allPages = pagemodule.Module.AllPages.ToString();
|
||||||
|
createdby = pagemodule.Module.CreatedBy;
|
||||||
|
createdon = pagemodule.Module.CreatedOn;
|
||||||
|
modifiedby = pagemodule.Module.ModifiedBy;
|
||||||
|
modifiedon = pagemodule.Module.ModifiedOn;
|
||||||
|
_permissions = pagemodule.Module.PermissionList;
|
||||||
|
|
||||||
|
if (pagemodule.Module.ModuleDefinition != null)
|
||||||
|
{
|
||||||
|
_module = pagemodule.Module.ModuleDefinition.Name;
|
||||||
|
_permissionNames = pagemodule.Module.ModuleDefinition?.PermissionNames;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(pagemodule.Module.ModuleDefinition.SettingsType))
|
||||||
{
|
{
|
||||||
// module settings type explicitly declared in IModule interface
|
// module settings type explicitly declared in IModule interface
|
||||||
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
|
_moduleSettingsType = Type.GetType(pagemodule.Module.ModuleDefinition.SettingsType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module )
|
// legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module )
|
||||||
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
|
_moduleSettingsType = Type.GetType(pagemodule.Module.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
|
||||||
}
|
}
|
||||||
if (_moduleSettingsType != null)
|
if (_moduleSettingsType != null)
|
||||||
{
|
{
|
||||||
@ -217,7 +247,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error);
|
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], pagemodule.Module.ModuleDefinitionName), MessageType.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
||||||
@ -241,6 +271,7 @@
|
|||||||
|
|
||||||
private async Task SaveModule()
|
private async Task SaveModule()
|
||||||
{
|
{
|
||||||
|
|
||||||
validated = true;
|
validated = true;
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
if (await interop.FormValid(form))
|
if (await interop.FormValid(form))
|
||||||
@ -261,21 +292,23 @@
|
|||||||
pagemodule.ExpiryDate = Utilities.LocalDateAndTimeAsUtc(_expirydate);
|
pagemodule.ExpiryDate = Utilities.LocalDateAndTimeAsUtc(_expirydate);
|
||||||
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
|
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
|
||||||
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
|
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
|
||||||
{
|
{
|
||||||
pagemodule.ContainerType = string.Empty;
|
pagemodule.ContainerType = string.Empty;
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
|
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
|
||||||
{
|
{
|
||||||
pagemodule.ContainerType = string.Empty;
|
pagemodule.ContainerType = string.Empty;
|
||||||
}
|
}
|
||||||
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
pagemodule.Header = _header;
|
||||||
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
|
pagemodule.Footer = _footer;
|
||||||
|
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
||||||
|
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
|
||||||
|
|
||||||
var module = ModuleState;
|
var module = await ModuleService.GetModuleAsync(ModuleState.ModuleId);
|
||||||
module.AllPages = bool.Parse(_allPages);
|
module.AllPages = bool.Parse(_allPages);
|
||||||
module.PageModuleId = ModuleState.PageModuleId;
|
module.PageModuleId = ModuleState.PageModuleId;
|
||||||
module.PermissionList = _permissionGrid.GetPermissionList();
|
module.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
await ModuleService.UpdateModuleAsync(module);
|
await ModuleService.UpdateModuleAsync(module);
|
||||||
|
|
||||||
if (_moduleSettingsType != null)
|
if (_moduleSettingsType != null)
|
||||||
{
|
{
|
||||||
@ -300,11 +333,13 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_activetab = "Settings";
|
||||||
AddModuleMessage(Localizer["Message.Required.Title"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.Required.Title"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_activetab = "Settings";
|
||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
|
<Label Class="col-sm-3" For="name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="name" class="form-control" @bind="@_name" required />
|
<input id="name" class="form-control" @bind="@_name" maxlength="50" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
@ -101,13 +101,13 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" 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. If the page is intended to be the root path specify '/'." ResourceKey="UrlPath">Url Path: </Label>
|
<Label Class="col-sm-3" 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. If the page is intended to be the root path specify '/'." ResourceKey="UrlPath">Url Path: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="path" class="form-control" @bind="@_path" />
|
<input id="path" class="form-control" @bind="@_path" maxlength="256" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="url" HelpText="Optionally enter a url which this page should redirect to when a user navigates to it" ResourceKey="Redirect">Redirect: </Label>
|
<Label Class="col-sm-3" For="url" HelpText="Optionally enter a url which this page should redirect to when a user navigates to it" ResourceKey="Redirect">Redirect: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="url" class="form-control" @bind="@_url" />
|
<input id="url" class="form-control" @bind="@_url" maxlength="500" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -147,7 +147,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
|
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="title" class="form-control" @bind="@_title" />
|
<input id="title" class="form-control" @bind="@_title" maxlength="200" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -186,13 +186,13 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
|
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3" maxlength="4000"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="bodycontent" HelpText="Optionally enter content to be included in the page body (ie. script tags)" ResourceKey="BodyContent">Body Content: </Label>
|
<Label Class="col-sm-3" For="bodycontent" HelpText="Optionally enter content to be included in the page body (ie. script tags)" ResourceKey="BodyContent">Body Content: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3"></textarea>
|
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3" maxlength="4000"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -316,10 +316,11 @@
|
|||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThemeChanged(ChangeEventArgs e)
|
private async Task ThemeChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_themetype = (string)e.Value;
|
_themetype = (string)e.Value;
|
||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
@ -330,6 +331,7 @@
|
|||||||
if (ThemeService.GetTheme(PageState.Site.Themes, _themetype)?.ThemeName != ThemeService.GetTheme(PageState.Site.Themes, PageState.Site.DefaultThemeType)?.ThemeName)
|
if (ThemeService.GetTheme(PageState.Site.Themes, _themetype)?.ThemeName != ThemeService.GetTheme(PageState.Site.Themes, PageState.Site.DefaultThemeType)?.ThemeName)
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["ThemeChanged.Message"], MessageType.Warning);
|
AddModuleMessage(Localizer["ThemeChanged.Message"], MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,6 +347,7 @@
|
|||||||
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
|
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
|
||||||
{
|
{
|
||||||
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(_themetype) && !string.IsNullOrEmpty(_containertype))
|
if (!string.IsNullOrEmpty(_themetype) && !string.IsNullOrEmpty(_containertype))
|
||||||
@ -395,12 +398,14 @@
|
|||||||
if (_pages.Any(item => item.Path == page.Path))
|
if (_pages.Any(item => item.Path == page.Path))
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page.ParentId == null && Constants.ReservedRoutes.Contains(page.Name.ToLower()))
|
if (page.ParentId == null && Constants.ReservedRoutes.Contains(page.Name.ToLower()))
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Message.Page.Reserved"], page.Name), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Message.Page.Reserved"], page.Name), MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,6 +473,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.Required.PageInfo"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.Required.PageInfo"], MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -475,11 +481,13 @@
|
|||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Saving Page {Page} {Error}", page, ex.Message);
|
await logger.LogError(ex, "Error Saving Page {Page} {Error}", page, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Page.Save"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Page.Save"], MessageType.Error);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,16 +30,16 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="parent" HelpText="Select the parent for the page in the site hierarchy" ResourceKey="Parent">Parent: </Label>
|
<Label Class="col-sm-3" For="parent" HelpText="Select the parent for the page in the site hierarchy" ResourceKey="Parent">Parent: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
|
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
|
||||||
<option value="-1"><@Localizer["SiteRoot"]></option>
|
<option value="-1"><@Localizer["SiteRoot"]></option>
|
||||||
@foreach (Page page in _pages)
|
@foreach (Page page in _pages)
|
||||||
|
{
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList) && page.PageId != _pageId)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList) && page.PageId != _pageId)
|
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
||||||
{
|
|
||||||
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</select>
|
}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -116,7 +116,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" 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. If the page is intended to be the root path specify '/'." ResourceKey="UrlPath">Url Path: </Label>
|
<Label Class="col-sm-3" 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. Please note that spaces and punctuation will be replaced by a dash. If the page is intended to be the root path specify '/'." ResourceKey="UrlPath">Url Path: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="path" class="form-control" @bind="@_path" maxlength="256" />
|
<input id="path" class="form-control" @bind="@_path" maxlength="256" />
|
||||||
</div>
|
</div>
|
||||||
@ -205,18 +205,21 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
|
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3" maxlength="4000"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="bodycontent" HelpText="Optionally enter content to be included in the page body (ie. script tags)" ResourceKey="BodyContent">Body Content: </Label>
|
<Label Class="col-sm-3" For="bodycontent" HelpText="Optionally enter content to be included in the page body (ie. script tags)" ResourceKey="BodyContent">Body Content: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3"></textarea>
|
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3" maxlength="4000"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<br />
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@ -225,15 +228,28 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<PermissionGrid EntityName="@EntityNames.Page" PermissionList="@_permissions" @ref="_permissionGrid" />
|
<PermissionGrid EntityName="@EntityNames.Page" PermissionList="@_permissions" @ref="_permissionGrid" />
|
||||||
</div>
|
</div>
|
||||||
|
<br /><br />
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="updatemodulepermissions" HelpText="Specify if changes made to page permissions should be propagated to the modules on this page" ResourceKey="UpdateModulePermissions">Update Module Permissions? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="updatemodulepermissions" class="form-select" @bind="@_updatemodulepermissions" required>
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="PageModules" Heading="Modules" ResourceKey="PageModules">
|
<TabPanel Name="PageModules" Heading="Modules" ResourceKey="PageModules">
|
||||||
<Pager Items="_pageModules">
|
<Pager Items="_pageModules">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@Localizer["ModuleTitle"]</th>
|
<th>@Localizer["ModuleTitle"]</th>
|
||||||
<th>@Localizer["ModuleDefinition"]</th>
|
<th>@Localizer["ModuleDefinition"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Settings" Text="Edit" Path="@_actualpath" ModuleId="@context.ModuleId" Security="SecurityAccessLevel.Edit" PermissionList="@context.PermissionList" ResourceKey="ModuleSettings" /></td>
|
<td><ActionLink Action="Settings" Text="Edit" Path="@_actualpath" ModuleId="@context.ModuleId" Security="SecurityAccessLevel.Edit" PermissionList="@context.PermissionList" ResourceKey="ModuleSettings" /></td>
|
||||||
@ -247,8 +263,10 @@
|
|||||||
{
|
{
|
||||||
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
|
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
|
||||||
@_themeSettingsComponent
|
@_themeSettingsComponent
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<br />
|
|
||||||
}
|
}
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
}
|
}
|
||||||
@ -263,6 +281,12 @@
|
|||||||
<input id="title" class="form-control" @bind="@_title" maxlength="200" />
|
<input id="title" class="form-control" @bind="@_title" maxlength="200" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="path" HelpText="Provide a url path for your personalized page. Please note that spaces and punctuation will be replaced by a dash." ResourceKey="PersonalizedUrlPath">Url Path: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="path" class="form-control" @bind="@_path" maxlength="256" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -293,19 +317,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@if (_themeSettingsType != null)
|
@if (_themeSettingsType != null)
|
||||||
{
|
{
|
||||||
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
|
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
|
||||||
@_themeSettingsComponent
|
@_themeSettingsComponent
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<br />
|
|
||||||
}
|
}
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
}
|
}
|
||||||
<br />
|
|
||||||
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,6 +368,7 @@
|
|||||||
private string _bodycontent;
|
private string _bodycontent;
|
||||||
private List<Permission> _permissions = null;
|
private List<Permission> _permissions = null;
|
||||||
private PermissionGrid _permissionGrid;
|
private PermissionGrid _permissionGrid;
|
||||||
|
private string _updatemodulepermissions;
|
||||||
private List<Module> _pageModules;
|
private List<Module> _pageModules;
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
private DateTime _createdon;
|
private DateTime _createdon;
|
||||||
@ -430,6 +457,7 @@
|
|||||||
|
|
||||||
// permissions
|
// permissions
|
||||||
_permissions = _page.PermissionList;
|
_permissions = _page.PermissionList;
|
||||||
|
_updatemodulepermissions = "True";
|
||||||
|
|
||||||
// page modules
|
// page modules
|
||||||
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
|
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
|
||||||
@ -466,7 +494,7 @@
|
|||||||
_parentid = (string)e.Value;
|
_parentid = (string)e.Value;
|
||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||||
{
|
{
|
||||||
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
@ -479,10 +507,11 @@
|
|||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThemeChanged(ChangeEventArgs e)
|
private async Task ThemeChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_themetype = (string)e.Value;
|
_themetype = (string)e.Value;
|
||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
@ -494,6 +523,7 @@
|
|||||||
if (ThemeService.GetTheme(PageState.Site.Themes, _themetype)?.ThemeName != ThemeService.GetTheme(PageState.Site.Themes, PageState.Site.DefaultThemeType)?.ThemeName)
|
if (ThemeService.GetTheme(PageState.Site.Themes, _themetype)?.ThemeName != ThemeService.GetTheme(PageState.Site.Themes, PageState.Site.DefaultThemeType)?.ThemeName)
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["ThemeChanged.Message"], MessageType.Warning);
|
AddModuleMessage(Localizer["ThemeChanged.Message"], MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,6 +561,7 @@
|
|||||||
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
|
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
|
||||||
{
|
{
|
||||||
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||||
@ -581,12 +612,14 @@
|
|||||||
if (_pages.Any(item => item.Path == _page.Path && item.PageId != _page.PageId))
|
if (_pages.Any(item => item.Path == _page.Path && item.PageId != _page.PageId))
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_page.ParentId == null && Constants.ReservedRoutes.Contains(_page.Name.ToLower()))
|
if (_page.ParentId == null && Constants.ReservedRoutes.Contains(_page.Name.ToLower()))
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Message.Page.Reserved"], _page.Name), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Message.Page.Reserved"], _page.Name), MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,6 +673,7 @@
|
|||||||
if (_page.UserId == null)
|
if (_page.UserId == null)
|
||||||
{
|
{
|
||||||
_page.PermissionList = _permissionGrid.GetPermissionList();
|
_page.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
|
_page.UpdateModulePermissions = bool.Parse(_updatemodulepermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
_page = await PageService.UpdatePageAsync(_page);
|
_page = await PageService.UpdatePageAsync(_page);
|
||||||
@ -671,17 +705,20 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.Required.PageInfo"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.Required.PageInfo"], MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Saving Page {Page} {Error}", _page, ex.Message);
|
await logger.LogError(ex, "Error Saving Page {Page} {Error}", _page, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Page.Save"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Page.Save"], MessageType.Error);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,71 +13,71 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Pages" ResourceKey="Pages" Heading="Pages">
|
<TabPanel Name="Pages" ResourceKey="Pages" Heading="Pages">
|
||||||
@if (!_pages.Where(item => item.IsDeleted).Any())
|
@if (!_pages.Where(item => item.IsDeleted).Any())
|
||||||
{
|
{
|
||||||
<br />
|
<br />
|
||||||
<p>@Localizer["NoPage.Deleted"]</p>
|
<p>@Localizer["NoPage.Deleted"]</p>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<Pager Items="@_pages.Where(item => item.IsDeleted).OrderByDescending(item => item.DeletedOn)" CurrentPage="@_pagePage.ToString()" OnPageChange="OnPageChangePage">
|
<Pager Items="@_pages.Where(item => item.IsDeleted).OrderByDescending(item => item.DeletedOn)" CurrentPage="@_pagePage.ToString()" OnPageChange="OnPageChangePage">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Path"]</th>
|
||||||
<th>@Localizer["DeletedBy"]</th>
|
<th>@Localizer["DeletedBy"]</th>
|
||||||
<th>@Localizer["DeletedOn"]</th>
|
<th>@Localizer["DeletedOn"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
|
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
|
||||||
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Path</td>
|
||||||
<td>@context.DeletedBy</td>
|
<td>@context.DeletedBy</td>
|
||||||
<td>@context.DeletedOn</td>
|
<td>@context.DeletedOn</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
<br />
|
<br />
|
||||||
<ActionDialog Header="Remove All Deleted Pages" Message="Are You Sure You Wish To Permanently Remove All Deleted Pages?" Action="Remove All Deleted Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
<ActionDialog Header="Remove All Deleted Pages" Message="Are You Sure You Wish To Permanently Remove All Deleted Pages?" Action="Remove All Deleted Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Modules" ResourceKey="Modules" Heading="Modules">
|
<TabPanel Name="Modules" ResourceKey="Modules" Heading="Modules">
|
||||||
@if (!_modules.Where(item => item.IsDeleted).Any())
|
@if (!_modules.Where(item => item.IsDeleted).Any())
|
||||||
{
|
{
|
||||||
<br />
|
<br />
|
||||||
<p>@Localizer["NoModule.Deleted"]</p>
|
<p>@Localizer["NoModule.Deleted"]</p>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<Pager Items="@_modules.Where(item => item.IsDeleted).OrderByDescending(item => item.DeletedOn)" CurrentPage="@_pageModule.ToString()" OnPageChange="OnPageChangeModule">
|
<Pager Items="@_modules.Where(item => item.IsDeleted).OrderByDescending(item => item.DeletedOn)" CurrentPage="@_pageModule.ToString()" OnPageChange="OnPageChangeModule">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@Localizer["Page"]</th>
|
<th>@Localizer["Page"]</th>
|
||||||
<th>@Localizer["Module"]</th>
|
<th>@Localizer["Module"]</th>
|
||||||
<th>@Localizer["DeletedBy"]</th>
|
<th>@Localizer["DeletedBy"]</th>
|
||||||
<th>@Localizer["DeletedOn"]</th>
|
<th>@Localizer["DeletedOn"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
|
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
|
||||||
<td><ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete"], context.Title)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
<td><ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete"], context.Title)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
||||||
<td>@_pages.Find(item => item.PageId == context.PageId).Name</td>
|
<td>@_pages.Find(item => item.PageId == context.PageId).Name</td>
|
||||||
<td>@context.Title</td>
|
<td>@context.Title</td>
|
||||||
<td>@context.DeletedBy</td>
|
<td>@context.DeletedBy</td>
|
||||||
<td>@context.DeletedOn</td>
|
<td>@context.DeletedOn</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
<br />
|
<br />
|
||||||
<ActionDialog Header="Remove All Deleted Modules" Message="Are You Sure You Wish To Permanently Remove All Deleted Modules?" Action="Remove All Deleted Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
|
<ActionDialog Header="Remove All Deleted Modules" Message="Are You Sure You Wish To Permanently Remove All Deleted Modules?" Action="Remove All Deleted Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
|
||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Page> _pages;
|
private List<Page> _pages;
|
||||||
private List<Module> _modules;
|
private List<Module> _modules;
|
||||||
private int _pagePage = 1;
|
private int _pagePage = 1;
|
||||||
private int _pageModule = 1;
|
private int _pageModule = 1;
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
@ -105,12 +105,25 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
page.IsDeleted = false;
|
var validated = true;
|
||||||
await PageService.UpdatePageAsync(page);
|
if (page.ParentId != null)
|
||||||
await logger.LogInformation("Page Restored {Page}", page);
|
{
|
||||||
await Load();
|
var parent = _pages.Find(item => item.PageId == page.ParentId);
|
||||||
StateHasChanged();
|
validated = !parent.IsDeleted;
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
}
|
||||||
|
if (validated)
|
||||||
|
{
|
||||||
|
page.IsDeleted = false;
|
||||||
|
await PageService.UpdatePageAsync(page);
|
||||||
|
await logger.LogInformation("Page Restored {Page}", page);
|
||||||
|
AddModuleMessage(Localizer["Success.Page.Restore"], MessageType.Success);
|
||||||
|
await Load();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Page.Restore"], MessageType.Warning);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -125,9 +138,9 @@ else
|
|||||||
{
|
{
|
||||||
await PageService.DeletePageAsync(page.PageId);
|
await PageService.DeletePageAsync(page.PageId);
|
||||||
await logger.LogInformation("Page Permanently Deleted {Page}", page);
|
await logger.LogInformation("Page Permanently Deleted {Page}", page);
|
||||||
|
AddModuleMessage(Localizer["Success.Page.Delete"], MessageType.Success);
|
||||||
await Load();
|
await Load();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -148,10 +161,10 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
await logger.LogInformation("Pages Permanently Deleted");
|
await logger.LogInformation("Pages Permanently Deleted");
|
||||||
|
AddModuleMessage(Localizer["Success.Pages.Delete"], MessageType.Success);
|
||||||
await Load();
|
await Load();
|
||||||
HideProgressIndicator();
|
HideProgressIndicator();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -169,6 +182,7 @@ else
|
|||||||
pagemodule.IsDeleted = false;
|
pagemodule.IsDeleted = false;
|
||||||
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
||||||
await logger.LogInformation("Module Restored {Module}", module);
|
await logger.LogInformation("Module Restored {Module}", module);
|
||||||
|
AddModuleMessage(Localizer["Success.Module.Restore"], MessageType.Success);
|
||||||
await Load();
|
await Load();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
@ -185,6 +199,7 @@ else
|
|||||||
{
|
{
|
||||||
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
||||||
await logger.LogInformation("Module Permanently Deleted {Module}", module);
|
await logger.LogInformation("Module Permanently Deleted {Module}", module);
|
||||||
|
AddModuleMessage(Localizer["Success.Module.Delete"], MessageType.Success);
|
||||||
await Load();
|
await Load();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
@ -205,6 +220,7 @@ else
|
|||||||
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
||||||
}
|
}
|
||||||
await logger.LogInformation("Modules Permanently Deleted");
|
await logger.LogInformation("Modules Permanently Deleted");
|
||||||
|
AddModuleMessage(Localizer["Success.Modules.Delete"], MessageType.Success);
|
||||||
await Load();
|
await Load();
|
||||||
HideProgressIndicator();
|
HideProgressIndicator();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
@ -3,80 +3,98 @@
|
|||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
|
@inject ITimeZoneService TimeZoneService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
|
||||||
@if (PageState.Site.AllowRegistration)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
if (!_userCreated)
|
@if (PageState.Site.AllowRegistration)
|
||||||
{
|
{
|
||||||
if (PageState.User != null)
|
if (!_userCreated)
|
||||||
{
|
{
|
||||||
<ModuleMessage Message="@Localizer["Info.Registration.Exists"]" Type="MessageType.Info" />
|
if (PageState.User != null)
|
||||||
}
|
{
|
||||||
else
|
<ModuleMessage Message="@Localizer["Info.Registration.Exists"]" Type="MessageType.Info" />
|
||||||
{
|
}
|
||||||
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
else
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
{
|
||||||
<div class="container">
|
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
||||||
<div class="row mb-1 align-items-center">
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<Label Class="col-sm-3" For="username" HelpText="Your username. Note that this field can not be modified once it is saved." ResourceKey="Username"></Label>
|
<div class="container">
|
||||||
<div class="col-sm-9">
|
<div class="row mb-1 align-items-center">
|
||||||
<input id="username" class="form-control" @bind="@_username" maxlength="256" required />
|
<Label Class="col-sm-3" For="username" HelpText="Your username. Note that this field can not be modified once it is saved." ResourceKey="Username"></Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="username" class="form-control" @bind="@_username" maxlength="256" required />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="row mb-1 align-items-center">
|
||||||
<div class="row mb-1 align-items-center">
|
<Label Class="col-sm-3" For="password" HelpText="Please choose a sufficiently secure password and enter it here" ResourceKey="Password"></Label>
|
||||||
<Label Class="col-sm-3" For="password" HelpText="Please choose a sufficiently secure password and enter it here" ResourceKey="Password"></Label>
|
<div class="col-sm-9">
|
||||||
<div class="col-sm-9">
|
<div class="input-group">
|
||||||
<div class="input-group">
|
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
|
||||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="confirm" HelpText="Enter your password again to confirm it matches the value entered above" ResourceKey="Confirm"></Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to receive notifications" ResourceKey="Email"></Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="email" class="form-control" @bind="@_email" maxlength="256" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="displayname" HelpText="Your full name" ResourceKey="DisplayName"></Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="displayname" class="form-control" @bind="@_displayname" maxlength="50" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="timezone" HelpText="Your time zone" ResourceKey="TimeZone">Time Zone:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="timezone" class="form-select" @bind="@_timezoneid">
|
||||||
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var timezone in _timezones)
|
||||||
|
{
|
||||||
|
<option value="@timezone.Id">@timezone.DisplayName</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="confirm" HelpText="Enter your password again to confirm it matches the value entered above" ResourceKey="Confirm"></Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<div class="input-group">
|
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to receive notifications" ResourceKey="Email"></Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="email" class="form-control" @bind="@_email" maxlength="256" required />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="displayname" HelpText="Your full name" ResourceKey="DisplayName"></Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="displayname" class="form-control" @bind="@_displayname" maxlength="50" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="Register">@Localizer["Register"]</button>
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
|
||||||
@if (_allowsitelogin)
|
|
||||||
{
|
|
||||||
<br />
|
<br />
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="Register">@Localizer["Register"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
|
@if (_allowsitelogin)
|
||||||
|
{
|
||||||
|
<br />
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<NavLink href="@NavigateUrl("login")">@Localizer["Login"]</NavLink>
|
<NavLink href="@NavigateUrl("login")">@Localizer["Login"]</NavLink>
|
||||||
}
|
}
|
||||||
</form>
|
</form>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
<ModuleMessage Message="@Localizer["Info.Registration.Disabled"]" Type="MessageType.Info" />
|
||||||
<ModuleMessage Message="@Localizer["Info.Registration.Disabled"]" Type="MessageType.Info" />
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private bool _initialized = false;
|
||||||
|
private List<Models.TimeZone> _timezones;
|
||||||
private string _passwordrequirements;
|
private string _passwordrequirements;
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
@ -87,6 +105,7 @@ else
|
|||||||
private string _confirm = string.Empty;
|
private string _confirm = string.Empty;
|
||||||
private string _email = string.Empty;
|
private string _email = string.Empty;
|
||||||
private string _displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
|
private string _timezoneid = string.Empty;
|
||||||
private bool _userCreated = false;
|
private bool _userCreated = false;
|
||||||
private bool _allowsitelogin = true;
|
private bool _allowsitelogin = true;
|
||||||
|
|
||||||
@ -96,6 +115,9 @@ else
|
|||||||
{
|
{
|
||||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||||
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
|
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
|
||||||
|
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||||
|
_timezoneid = PageState.Site.TimeZoneId;
|
||||||
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
@ -124,6 +146,7 @@ else
|
|||||||
Password = _password,
|
Password = _password,
|
||||||
Email = _email,
|
Email = _email,
|
||||||
DisplayName = (_displayname == string.Empty ? _username : _displayname),
|
DisplayName = (_displayname == string.Empty ? _username : _displayname),
|
||||||
|
TimeZoneId = _timezoneid,
|
||||||
PhotoFileId = null
|
PhotoFileId = null
|
||||||
};
|
};
|
||||||
user = await UserService.AddUserAsync(user);
|
user = await UserService.AddUserAsync(user);
|
||||||
|
@ -58,7 +58,7 @@ else
|
|||||||
<td>@context.EffectiveDate</td>
|
<td>@context.EffectiveDate</td>
|
||||||
<td>@context.ExpiryDate</td>
|
<td>@context.ExpiryDate</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || context.User.Username == UserNames.Host || context.User.UserId == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
|
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.User.Username == UserNames.Host || context.User.UserId == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
|
||||||
</td>
|
</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
@ -180,27 +180,28 @@ else
|
|||||||
|
|
||||||
private async Task DeleteUserRole(int UserRoleId)
|
private async Task DeleteUserRole(int UserRoleId)
|
||||||
{
|
{
|
||||||
validated = true;
|
try
|
||||||
var interop = new Interop(JSRuntime);
|
|
||||||
if (await interop.FormValid(form))
|
|
||||||
{
|
{
|
||||||
try
|
var userrole = await UserRoleService.GetUserRoleAsync(UserRoleId);
|
||||||
|
if (userrole.Role.Name == RoleNames.Registered)
|
||||||
|
{
|
||||||
|
userrole.ExpiryDate = DateTime.UtcNow;
|
||||||
|
await UserRoleService.UpdateUserRoleAsync(userrole);
|
||||||
|
await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
|
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
|
||||||
await logger.LogInformation("User Removed From Role {UserRoleId}", UserRoleId);
|
await logger.LogInformation("User {Username} Removed From Role {Role}", userrole.User.Username, userrole.Role.Name);
|
||||||
AddModuleMessage(Localizer["Confirm.User.RoleRemoved"], MessageType.Success);
|
|
||||||
await GetUserRoles();
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Removing User From Role {UserRoleId} {Error}", UserRoleId, ex.Message);
|
|
||||||
AddModuleMessage(Localizer["Error.User.RemoveRole"], MessageType.Error);
|
|
||||||
}
|
}
|
||||||
|
AddModuleMessage(Localizer["Confirm.User.RoleRemoved"], MessageType.Success);
|
||||||
|
await GetUserRoles();
|
||||||
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
else
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
await logger.LogError(ex, "Error Removing User From Role {UserRoleId} {Error}", UserRoleId, ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.User.RemoveRole"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
private string _enabled = "True";
|
private string _enabled = "True";
|
||||||
private string _lastIndexedOn = "";
|
private string _lastIndexedOn = "";
|
||||||
private string _ignorePages = "";
|
private string _ignorePages = "";
|
||||||
private string _ignoreEntities = "";
|
private string _ignoreEntities = "File";
|
||||||
private string _minimumWordLength = "3";
|
private string _minimumWordLength = "3";
|
||||||
private string _ignoreWords = "the,be,to,of,and,a,i,in,that,have,it,for,not,on,with,he,as,you,do,at,this,but,his,by,from,they,we,say,her,she,or,an,will,my,one,all,would,there,their,what,so,up,out,if,about,who,get,which,go,me,when,make,can,like,time,no,just,him,know,take,people,into,year,your,good,some,could,them,see,other,than,then,now,look,only,come,its,over,think,also,back,after,use,two,how,our,work,first,well,way,even,new,want,because,any,these,give,day,most,us";
|
private string _ignoreWords = "the,be,to,of,and,a,i,in,that,have,it,for,not,on,with,he,as,you,do,at,this,but,his,by,from,they,we,say,her,she,or,an,will,my,one,all,would,there,their,what,so,up,out,if,about,who,get,which,go,me,when,make,can,like,time,no,just,him,know,take,people,into,year,your,good,some,could,them,see,other,than,then,now,look,only,come,its,over,think,also,back,after,use,two,how,our,work,first,well,way,even,new,want,because,any,these,give,day,most,us";
|
||||||
|
|
||||||
@ -85,7 +85,7 @@
|
|||||||
{
|
{
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
settings = SettingService.SetSetting(settings, "Search_SearchProvider", _searchProvider);
|
settings = SettingService.SetSetting(settings, "Search_SearchProvider", _searchProvider);
|
||||||
settings = SettingService.SetSetting(settings, "Search_Enabled", _enabled, true);
|
settings = SettingService.SetSetting(settings, "Search_Enabled", _enabled);
|
||||||
settings = SettingService.SetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn, true);
|
settings = SettingService.SetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn, true);
|
||||||
settings = SettingService.SetSetting(settings, "Search_IgnorePages", _ignorePages, true);
|
settings = SettingService.SetSetting(settings, "Search_IgnorePages", _ignorePages, true);
|
||||||
settings = SettingService.SetSetting(settings, "Search_IgnoreEntities", _ignoreEntities, true);
|
settings = SettingService.SetSetting(settings, "Search_IgnoreEntities", _ignoreEntities, true);
|
||||||
@ -106,9 +106,7 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_lastIndexedOn = DateTime.MinValue.ToString();
|
_lastIndexedOn = DateTime.MinValue.ToString();
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
await Save();
|
||||||
settings = SettingService.SetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn, true);
|
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
|
||||||
AddModuleMessage(Localizer["Message.Reindex"], MessageType.Success);
|
AddModuleMessage(Localizer["Message.Reindex"], MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -10,10 +10,12 @@
|
|||||||
@inject IAliasService AliasService
|
@inject IAliasService AliasService
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
@inject ITimeZoneService TimeZoneService
|
||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject INotificationService NotificationService
|
@inject INotificationService NotificationService
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
@inject IOutputCacheService CacheService
|
||||||
|
|
||||||
@if (_initialized)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
@ -32,32 +34,45 @@
|
|||||||
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
||||||
@foreach (Page page in _pages)
|
@foreach (Page page in _pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||||
{
|
{
|
||||||
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Deleted? </Label>
|
<Label Class="col-sm-3" For="timezone" HelpText="Your time zone" ResourceKey="TimeZone">Time Zone:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
|
<select id="timezone" class="form-select" @bind="@_timezoneid">
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
@foreach (var timezone in _timezones)
|
||||||
</select>
|
{
|
||||||
</div>
|
<option value="@timezone.Id">@timezone.DisplayName</option>
|
||||||
</div>
|
}
|
||||||
<div class="row mb-1 align-items-center">
|
</select>
|
||||||
<Label Class="col-sm-3" For="sitemap" HelpText="The site map url for this site which can be submitted to search engines for indexing" ResourceKey="SiteMap">Site Map: </Label>
|
</div>
|
||||||
<div class="col-sm-9">
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Deleted? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="sitemap" HelpText="The site map url for this site which can be submitted to search engines for indexing. The sitemap is cached for 5 minutes and the cache can be manually cleared." ResourceKey="SiteMap">Site Map: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="sitemap" class="form-control" @bind="@_sitemap" disabled />
|
<input id="sitemap" class="form-control" @bind="@_sitemap" disabled />
|
||||||
<a href="@_sitemap" class="btn btn-secondary" target="_new">@Localizer["Browse"]</a>
|
<a href="@_sitemap" class="btn btn-secondary" target="_new">@Localizer["Browse"]</a>
|
||||||
|
<button type="button" class="btn btn-danger" @onclick="EvictSitemapOutputCache">@Localizer["SiteMap.EvictCache"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="siteguid" HelpText="The Unique Identifier For The Site" ResourceKey="SiteGuid">ID: </Label>
|
<Label Class="col-sm-3" For="siteguid" HelpText="The Unique Identifier For The Site" ResourceKey="SiteGuid">ID: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -72,20 +87,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
|
<Section Name="Theme" Heading="Theme" ResourceKey="Theme">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<FileManager FileId="@_logofileid" Filter="@_imageFiles" @ref="_logofilemanager" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<FileManager FileId="@_faviconfileid" Filter="ico,png,gif" @ref="_faviconfilemanager" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
|
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -126,6 +129,32 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="cookieconsent" HelpText="Specify if cookie consent is enabled on this site. Please note this option must be used in conjunction with a Theme which supports cookie consent." ResourceKey="CookieConsent">Cookie Consent: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="cookieconsent" class="form-select" @bind="@_cookieconsent">
|
||||||
|
<option value="">@SharedLocalizer["Disabled"]</option>
|
||||||
|
<option value="optin">@Localizer["OptIn"]</option>
|
||||||
|
<option value="optout">@Localizer["OptOut"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<FileManager FileId="@_logofileid" Filter="@_imagefiles" @ref="_logofilemanager" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<FileManager FileId="@_faviconfileid" Filter="ico,png,gif" @ref="_faviconfilemanager" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="Functionality" Heading="Functionality" ResourceKey="Functionality">
|
<Section Name="Functionality" Heading="Functionality" ResourceKey="Functionality">
|
||||||
@ -144,23 +173,11 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="imageExt" HelpText="Enter a comma separated list of image file extensions" ResourceKey="ImageExtensions">Image Extensions: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="imageExt" spellcheck="false" class="form-control" @bind="@_imageFiles" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="uploadableFileExt" HelpText="Enter a comma separated list of uploadable file extensions" ResourceKey="UploadableFileExtensions">Uploadable File Extensions: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="uploadableFileExt" spellcheck="false" class="form-control" @bind="@_uploadableFiles" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="PageContent" Heading="Page Content" ResourceKey="PageContent">
|
<Section Name="PageContent" Heading="Page Content" ResourceKey="PageContent">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
|
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
|
||||||
@ -213,10 +230,10 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="password" HelpText="Enter the password for your SMTP account" ResourceKey="SmtpPassword">Password: </Label>
|
<Label Class="col-sm-3" For="password" HelpText="Enter the password for your SMTP account" ResourceKey="SmtpPassword">Password: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" autocomplete="off"/>
|
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" autocomplete="off"/>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword" tabindex="-1">@_togglesmtppassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword" tabindex="-1">@_togglesmtppassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -225,15 +242,15 @@
|
|||||||
<input id="sender" class="form-control" @bind="@_smtpsender" />
|
<input id="sender" class="form-control" @bind="@_smtpsender" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="relay" HelpText="Only specify this option if you have properly configured an SMTP Relay Service to route your outgoing mail. This option will send notifications from the user's email rather than from the Email Sender specified above." ResourceKey="SmtpRelay">Relay Configured? </Label>
|
<Label Class="col-sm-3" For="relay" HelpText="Only specify this option if you have properly configured an SMTP Relay Service to route your outgoing mail. This option will send notifications from the user's email rather than from the Email Sender specified above." ResourceKey="SmtpRelay">Relay Configured? </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="relay" class="form-select" @bind="@_smtprelay" required>
|
<select id="relay" class="form-select" @bind="@_smtprelay" required>
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="smtpenabled" HelpText="Specify if SMTP is enabled for this site" ResourceKey="SMTPEnabled">Enabled? </Label>
|
<Label Class="col-sm-3" For="smtpenabled" HelpText="Specify if SMTP is enabled for this site" ResourceKey="SMTPEnabled">Enabled? </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -244,10 +261,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
|
<Label Class="col-sm-3" For="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
|
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="SendEmail">@Localizer["Smtp.TestConfig"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="SendEmail">@Localizer["Smtp.TestConfig"]</button>
|
||||||
<br /><br />
|
<br /><br />
|
||||||
@ -280,57 +297,57 @@
|
|||||||
</Section>
|
</Section>
|
||||||
@if (_aliases != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
@if (_aliases != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
|
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="aliases" HelpText="The urls for the site. This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder)." ResourceKey="Aliases">Aliases: </Label>
|
<Label Class="col-sm-3" For="aliases" HelpText="The urls for the site. This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder)." ResourceKey="Aliases">Aliases: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<button type="button" class="btn btn-primary" @onclick="AddAlias">@SharedLocalizer["Add"]</button>
|
<button type="button" class="btn btn-primary" @onclick="AddAlias">@SharedLocalizer["Add"]</button>
|
||||||
<Pager Items="@_aliases">
|
<Pager Items="@_aliases">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@Localizer["AliasName"]</th>
|
<th>@Localizer["AliasName"]</th>
|
||||||
<th>@Localizer["AliasDefault"]</th>
|
<th>@Localizer["AliasDefault"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
@if (context.AliasId != _aliasid)
|
@if (context.AliasId != _aliasid)
|
||||||
{
|
{
|
||||||
<td>
|
<td>
|
||||||
@if (_aliasid == -1)
|
@if (_aliasid == -1)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-primary" @onclick="@(() => EditAlias(context))">@SharedLocalizer["Edit"]</button>
|
<button type="button" class="btn btn-primary" @onclick="@(() => EditAlias(context))">@SharedLocalizer["Edit"]</button>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if (_aliasid == -1)
|
@if (_aliasid == -1)
|
||||||
{
|
{
|
||||||
<ActionDialog Action="Delete" OnClick="@(async () => await DeleteAlias(context))" ResourceKey="DeleteAlias" Class="btn btn-danger" Header="Delete Alias" Message="@string.Format(Localizer["Confirm.Alias.Delete", context.Name])" />
|
<ActionDialog Action="Delete" OnClick="@(async () => await DeleteAlias(context))" ResourceKey="DeleteAlias" Class="btn btn-danger" Header="Delete Alias" Message="@string.Format(Localizer["Confirm.Alias.Delete", context.Name])" />
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@((context.IsDefault) ? SharedLocalizer["Yes"] : SharedLocalizer["No"])</td>
|
<td>@((context.IsDefault) ? SharedLocalizer["Yes"] : SharedLocalizer["No"])</td>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<td><button type="button" class="btn btn-success" @onclick="@(async () => await SaveAlias())">@SharedLocalizer["Save"]</button></td>
|
<td><button type="button" class="btn btn-success" @onclick="@(async () => await SaveAlias())">@SharedLocalizer["Save"]</button></td>
|
||||||
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => await CancelAlias())">@SharedLocalizer["Cancel"]</button></td>
|
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => await CancelAlias())">@SharedLocalizer["Cancel"]</button></td>
|
||||||
<td>
|
<td>
|
||||||
<input id="aliasname" class="form-control" @bind="@_aliasname" />
|
<input id="aliasname" class="form-control" @bind="@_aliasname" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
|
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
|
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -376,7 +393,7 @@
|
|||||||
<Section Name="TenantInformation" Heading="Database" ResourceKey="TenantInformation">
|
<Section Name="TenantInformation" Heading="Database" ResourceKey="TenantInformation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="tenant" HelpText="The name of the database used for the site. Note that this is not the physical database name but rather the tenant name which is used within the framework to identify a database." ResourceKey="Tenant">Database: </Label>
|
<Label Class="col-sm-3" For="tenant" HelpText="The name of the database used for the site. Note that this is not the physical database name but rather the tenant name which is used within the framework to identify a database." ResourceKey="Tenant">Database: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
||||||
</div>
|
</div>
|
||||||
@ -390,7 +407,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="connectionstring" HelpText="The name of the connection string in appsettings.json which will be used to connect to the database" ResourceKey="ConnectionString">Connection: </Label>
|
<Label Class="col-sm-3" For="connectionstring" HelpText="The name of the connection string in appsettings.json which will be used to connect to the database" ResourceKey="ConnectionString">Connection: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="connectionstring" class="form-control" @bind="@_connectionstring" readonly />
|
<input id="connectionstring" class="form-control" @bind="@_connectionstring" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -412,9 +429,11 @@
|
|||||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private List<Page> _pages;
|
private List<Page> _pages;
|
||||||
|
private List<Models.TimeZone> _timezones;
|
||||||
|
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
private string _homepageid = "-";
|
private string _homepageid = "-";
|
||||||
|
private string _timezoneid = string.Empty;
|
||||||
private string _isdeleted;
|
private string _isdeleted;
|
||||||
private string _sitemap = "";
|
private string _sitemap = "";
|
||||||
private string _siteguid = "";
|
private string _siteguid = "";
|
||||||
@ -427,11 +446,11 @@
|
|||||||
private string _themetype = "";
|
private string _themetype = "";
|
||||||
private string _containertype = "";
|
private string _containertype = "";
|
||||||
private string _admincontainertype = "";
|
private string _admincontainertype = "";
|
||||||
|
private string _cookieconsent = "";
|
||||||
|
|
||||||
private Dictionary<string, string> _textEditors = new Dictionary<string, string>();
|
private Dictionary<string, string> _textEditors = new Dictionary<string, string>();
|
||||||
private string _textEditor = "";
|
private string _textEditor = "";
|
||||||
private string _imageFiles = string.Empty;
|
private string _imagefiles = string.Empty;
|
||||||
private string _uploadableFiles = string.Empty;
|
|
||||||
|
|
||||||
private string _headcontent = string.Empty;
|
private string _headcontent = string.Empty;
|
||||||
private string _bodycontent = string.Empty;
|
private string _bodycontent = string.Empty;
|
||||||
@ -481,14 +500,21 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (PageState.QueryString.ContainsKey("updated"))
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success);
|
||||||
|
}
|
||||||
|
|
||||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||||
if (site != null)
|
if (site != null)
|
||||||
{
|
{
|
||||||
|
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||||
|
|
||||||
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
_name = site.Name;
|
_name = site.Name;
|
||||||
|
_timezoneid = site.TimeZoneId;
|
||||||
if (site.HomePageId != null)
|
if (site.HomePageId != null)
|
||||||
{
|
{
|
||||||
_homepageid = site.HomePageId.Value.ToString();
|
_homepageid = site.HomePageId.Value.ToString();
|
||||||
@ -513,6 +539,7 @@
|
|||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||||
|
_cookieconsent = SettingService.GetSetting(settings, "CookieConsent", string.Empty);
|
||||||
|
|
||||||
// functionality
|
// functionality
|
||||||
var textEditors = ServiceProvider.GetServices<ITextEditor>();
|
var textEditors = ServiceProvider.GetServices<ITextEditor>();
|
||||||
@ -521,10 +548,8 @@
|
|||||||
_textEditors.Add(textEditor.Name, Utilities.GetFullTypeName(textEditor.GetType().AssemblyQualifiedName));
|
_textEditors.Add(textEditor.Name, Utilities.GetFullTypeName(textEditor.GetType().AssemblyQualifiedName));
|
||||||
}
|
}
|
||||||
_textEditor = SettingService.GetSetting(settings, "TextEditor", Constants.DefaultTextEditor);
|
_textEditor = SettingService.GetSetting(settings, "TextEditor", Constants.DefaultTextEditor);
|
||||||
_imageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles);
|
_imagefiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles);
|
||||||
_imageFiles = (string.IsNullOrEmpty(_imageFiles)) ? Constants.ImageFiles : _imageFiles;
|
_imagefiles = (string.IsNullOrEmpty(_imagefiles)) ? Constants.ImageFiles : _imagefiles;
|
||||||
_uploadableFiles = SettingService.GetSetting(settings, "UploadableFiles", Constants.UploadableFiles);
|
|
||||||
_uploadableFiles = (string.IsNullOrEmpty(_uploadableFiles)) ? Constants.UploadableFiles : _uploadableFiles;
|
|
||||||
|
|
||||||
// page content
|
// page content
|
||||||
_headcontent = site.HeadContent;
|
_headcontent = site.HeadContent;
|
||||||
@ -642,6 +667,7 @@
|
|||||||
if (site != null)
|
if (site != null)
|
||||||
{
|
{
|
||||||
site.Name = _name;
|
site.Name = _name;
|
||||||
|
site.TimeZoneId = _timezoneid;
|
||||||
site.HomePageId = (_homepageid != "-" ? int.Parse(_homepageid) : null);
|
site.HomePageId = (_homepageid != "-" ? int.Parse(_homepageid) : null);
|
||||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||||
|
|
||||||
@ -727,16 +753,17 @@
|
|||||||
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
||||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
||||||
|
|
||||||
|
//cookie consent
|
||||||
|
settings = SettingService.SetSetting(settings, "CookieConsent", _cookieconsent);
|
||||||
|
|
||||||
// functionality
|
// functionality
|
||||||
settings = SettingService.SetSetting(settings, "TextEditor", _textEditor);
|
settings = SettingService.SetSetting(settings, "TextEditor", _textEditor);
|
||||||
settings = SettingService.SetSetting(settings, "ImageFiles", (_imageFiles != Constants.ImageFiles) ? _imageFiles.Replace(" ", "") : "", false);
|
|
||||||
settings = SettingService.SetSetting(settings, "UploadableFiles", (_uploadableFiles != Constants.UploadableFiles) ? _uploadableFiles.Replace(" ", "") : "", false);
|
|
||||||
|
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||||
|
|
||||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||||
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl(), true); // reload
|
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "updated=true"), true); // reload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -925,4 +952,9 @@
|
|||||||
_aliasname = "";
|
_aliasname = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task EvictSitemapOutputCache() {
|
||||||
|
await CacheService.EvictByTag(Constants.SitemapOutputCacheTag);
|
||||||
|
AddModuleMessage(Localizer["Success.SiteMap.CacheEvicted"], MessageType.Success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,16 +133,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="packageregistryurl" HelpText="Specify The Package Manager Service For Installing Modules, Themes, And Translations. If This Field Is Blank It Means The Package Manager Service Is Disabled For This Installation." ResourceKey="PackageManager">Package Manager: </Label>
|
<Label Class="col-sm-3" For="cachecontrol" HelpText="Provide a Cache-Control directive for static assets. For example 'public, max-age=60' indicates that static assets should be cached for 60 seconds. A blank value indicates caching is not enabled." ResourceKey="CacheControl">Static Asset Caching: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="cachecontrol" class="form-control" @bind="@_cachecontrol" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="packageregistryurl" HelpText="Specify The Url Of The Package Manager Service For Installing Modules, Themes, And Translations. If This Field Is Blank It Means The Package Manager Service Is Disabled For This Installation." ResourceKey="PackageManager">Package Manager Url: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="packageregistryurl" class="form-control" @bind="@_packageregistryurl" />
|
<input id="packageregistryurl" class="form-control" @bind="@_packageregistryurl" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="packageregistryemail" HelpText="Specify The Email Address Of The User Account Used For Interacting With The Package Manager Service. This Account Is Used For Managing Packages Across Multiple Installations." ResourceKey="PackageManagerEmail">Package Manager Email: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="packageregistryemail" class="form-control" @bind="@_packageregistryemail" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br /><br />
|
<br /><br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveConfig">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveConfig">@SharedLocalizer["Save"]</button>
|
||||||
<a class="btn btn-primary" href="swagger/index.html" target="_new">@Localizer["Access.ApiFramework"]</a>
|
|
||||||
<ActionDialog Header="Restart Application" Message="Are You Sure You Wish To Restart The Application?" Action="Restart Application" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await RestartApplication())" ResourceKey="RestartApplication" />
|
<ActionDialog Header="Restart Application" Message="Are You Sure You Wish To Restart The Application?" Action="Restart Application" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await RestartApplication())" ResourceKey="RestartApplication" />
|
||||||
|
<br /><br />
|
||||||
|
<a class="btn btn-primary" href="swagger/index.html" target="_new">@Localizer["Swagger"]</a>
|
||||||
|
<a class="btn btn-secondary" href="api/endpoint" target="_new">@Localizer["Endpoints"]</a>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Log" Heading="Log" ResourceKey="Log">
|
<TabPanel Name="Log" Heading="Log" ResourceKey="Log">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -179,9 +193,11 @@
|
|||||||
private string _logginglevel = string.Empty;
|
private string _logginglevel = string.Empty;
|
||||||
private string _notificationlevel = string.Empty;
|
private string _notificationlevel = string.Empty;
|
||||||
private string _swagger = string.Empty;
|
private string _swagger = string.Empty;
|
||||||
|
private string _cachecontrol = string.Empty;
|
||||||
private string _packageregistryurl = string.Empty;
|
private string _packageregistryurl = string.Empty;
|
||||||
|
private string _packageregistryemail = string.Empty;
|
||||||
|
|
||||||
private string _log = string.Empty;
|
private string _log = string.Empty;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
@ -209,9 +225,11 @@
|
|||||||
_detailederrors = systeminfo["DetailedErrors"].ToString();
|
_detailederrors = systeminfo["DetailedErrors"].ToString();
|
||||||
_logginglevel = systeminfo["Logging:LogLevel:Default"].ToString();
|
_logginglevel = systeminfo["Logging:LogLevel:Default"].ToString();
|
||||||
_notificationlevel = systeminfo["Logging:LogLevel:Notify"].ToString();
|
_notificationlevel = systeminfo["Logging:LogLevel:Notify"].ToString();
|
||||||
_swagger = systeminfo["UseSwagger"].ToString();
|
_swagger = systeminfo["UseSwagger"].ToString();
|
||||||
|
_cachecontrol = systeminfo["CacheControl"].ToString();
|
||||||
_packageregistryurl = systeminfo["PackageRegistryUrl"].ToString();
|
_packageregistryurl = systeminfo["PackageRegistryUrl"].ToString();
|
||||||
}
|
_packageregistryemail = systeminfo["PackageRegistryEmail"].ToString();
|
||||||
|
}
|
||||||
|
|
||||||
systeminfo = await SystemService.GetSystemInfoAsync("log");
|
systeminfo = await SystemService.GetSystemInfoAsync("log");
|
||||||
if (systeminfo != null)
|
if (systeminfo != null)
|
||||||
@ -229,8 +247,10 @@
|
|||||||
settings.Add("Logging:LogLevel:Default", _logginglevel);
|
settings.Add("Logging:LogLevel:Default", _logginglevel);
|
||||||
settings.Add("Logging:LogLevel:Notify", _notificationlevel);
|
settings.Add("Logging:LogLevel:Notify", _notificationlevel);
|
||||||
settings.Add("UseSwagger", _swagger);
|
settings.Add("UseSwagger", _swagger);
|
||||||
settings.Add("PackageRegistryUrl", _packageregistryurl);
|
settings.Add("CacheControl", _cachecontrol);
|
||||||
await SystemService.UpdateSystemInfoAsync(settings);
|
settings.Add("PackageRegistryUrl", _packageregistryurl);
|
||||||
|
settings.Add("PackageRegistryEmail", _packageregistryemail);
|
||||||
|
await SystemService.UpdateSystemInfoAsync(settings);
|
||||||
AddModuleMessage(Localizer["Success.UpdateConfig.Restart"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.UpdateConfig.Restart"], MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -45,24 +45,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this theme was installed. This value must be specified within the theme's ITheme interface specification." ResourceKey="PackageName">Package Name: </Label>
|
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this theme was installed. This value must be specified within the theme's ITheme interface specification." ResourceKey="PackageName">Package Name: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@if (!string.IsNullOrEmpty(_packagename))
|
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||||
{
|
|
||||||
<div class="input-group">
|
|
||||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
|
||||||
@if (string.IsNullOrEmpty(_packageurl))
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="ValidatePackage">@Localizer["Validate"]</button>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<a href="@_packageurl" target="_blank" class="btn btn-primary">@SharedLocalizer["Download"]</a>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -72,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="url" HelpText="The reference url of the theme" ResourceKey="ReferenceUrl">Reference Url: </Label>
|
<Label Class="col-sm-3" For="url" HelpText="The url of the theme" ResourceKey="Url">Url: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="url" class="form-control" @bind="@_url" disabled />
|
<input id="url" class="form-control" @bind="@_url" disabled />
|
||||||
</div>
|
</div>
|
||||||
@ -116,7 +99,6 @@
|
|||||||
private string _name;
|
private string _name;
|
||||||
private string _version;
|
private string _version;
|
||||||
private string _packagename = "";
|
private string _packagename = "";
|
||||||
private string _packageurl = "";
|
|
||||||
private string _owner = "";
|
private string _owner = "";
|
||||||
private string _url = "";
|
private string _url = "";
|
||||||
private string _contact = "";
|
private string _contact = "";
|
||||||
@ -185,27 +167,4 @@
|
|||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ValidatePackage()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var package = await PackageService.GetPackageAsync(_packagename, _version, true);
|
|
||||||
if (package == null || string.IsNullOrEmpty(package.PackageUrl))
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.Validate"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_packageurl = package.PackageUrl;
|
|
||||||
AddModuleMessage(Localizer["Message.Download"], MessageType.Info);
|
|
||||||
}
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packagename, _version);
|
|
||||||
AddModuleMessage(Localizer["Error.Validate"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
@inject IPackageService PackageService
|
@inject IPackageService PackageService
|
||||||
|
@inject ISiteService SiteService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@ -14,11 +15,12 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Install Theme" ResourceKey="InstallTheme" />
|
<ActionLink Action="Add" Text="Install Theme" ResourceKey="InstallTheme" />
|
||||||
@((MarkupString)" ")
|
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" Class="btn btn-secondary ps-2" />
|
||||||
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" Class="btn btn-secondary" />
|
<button type="button" class="btn btn-secondary pw-2" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
||||||
|
|
||||||
<Pager Items="@_themes">
|
<Pager Items="@_themes">
|
||||||
<Header>
|
<Header>
|
||||||
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
@ -32,10 +34,11 @@ else
|
|||||||
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditTheme" /></td>
|
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditTheme" /></td>
|
||||||
<td>
|
<td>
|
||||||
@if (context.AssemblyName != Constants.ClientId)
|
@if (context.AssemblyName != Constants.ClientId)
|
||||||
{
|
{
|
||||||
<ActionDialog Header="Delete Theme" Message="@string.Format(Localizer["Confirm.Theme.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteTheme(context))" ResourceKey="DeleteTheme" />
|
<ActionDialog Header="Delete Theme" Message="@string.Format(Localizer["Confirm.Theme.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteTheme(context))" ResourceKey="DeleteTheme" />
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
|
<td><NavLink class="btn btn-secondary" href="@NavigateUrl("admin/site")">@Localizer["Assign"]</NavLink></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@context.Version</td>
|
<td>@context.Version</td>
|
||||||
<td>
|
<td>
|
||||||
@ -170,4 +173,27 @@ else
|
|||||||
AddModuleMessage(Localizer["Error.Theme.Delete"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Theme.Delete"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task Synchronize()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ShowProgressIndicator();
|
||||||
|
foreach (var theme in _themes)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(theme.PackageName) && !_packages.Any(item => item.PackageId == theme.PackageName))
|
||||||
|
{
|
||||||
|
await PackageService.GetPackageAsync(theme.PackageName, theme.Version, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HideProgressIndicator();
|
||||||
|
AddModuleMessage(Localizer["Success.Theme.Synchronize"], MessageType.Success);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Synchronizing Themes {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Theme.Synchronize"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -13,9 +13,26 @@
|
|||||||
<TabPanel Name="Download" ResourceKey="Download">
|
<TabPanel Name="Download" ResourceKey="Download">
|
||||||
@if (_package != null && _upgradeavailable)
|
@if (_package != null && _upgradeavailable)
|
||||||
{
|
{
|
||||||
<ModuleMessage Type="MessageType.Info" Message="Select The Download Button To Download The Framework Upgrade Package And Then Select Upgrade"></ModuleMessage>
|
<div class="container">
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await Download(Constants.PackageId, @_package.Version))>@SharedLocalizer["Download"] @_package.Version</button>
|
<div class="row mb-1 align-items-center">
|
||||||
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
<Label Class="col-sm-3" HelpText="Specify if you want to backup files during the upgrade process. Disabling this option will reduce the time required for the upgrade." ResourceKey="Backup">Backup Files? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="backup" class="form-select" @bind="@_backup">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
@if (!_downloaded)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick=@(async () => await Download(Constants.PackageId, @_package.Version))>@SharedLocalizer["Download"] @_package.Version</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -23,7 +40,6 @@
|
|||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
<TabPanel Name="Upload" ResourceKey="Upload">
|
||||||
<ModuleMessage Type="MessageType.Info" Message=@Localizer["MessageUpgrade.Text"]></ModuleMessage>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" HelpText="Upload A Framework Package And Then Select Upgrade" ResourceKey="Framework">Framework: </Label>
|
<Label Class="col-sm-3" HelpText="Upload A Framework Package And Then Select Upgrade" ResourceKey="Framework">Framework: </Label>
|
||||||
@ -31,7 +47,17 @@
|
|||||||
<FileManager Folder="@Constants.PackagesFolder" />
|
<FileManager Folder="@Constants.PackagesFolder" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" HelpText="Specify if you want to backup files during the upgrade process. Disabling this option will reduce the time required for the upgrade." ResourceKey="Backup">Backup Files? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="backup" class="form-select" @bind="@_backup">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
@ -39,8 +65,10 @@
|
|||||||
|
|
||||||
@code {
|
@code {
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
|
private bool _downloaded = false;
|
||||||
private Package _package;
|
private Package _package;
|
||||||
private bool _upgradeavailable = false;
|
private bool _upgradeavailable = false;
|
||||||
|
private string _backup = "True";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
@ -86,7 +114,7 @@
|
|||||||
ShowProgressIndicator();
|
ShowProgressIndicator();
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
await interop.RedirectBrowser(NavigateUrl(), 10);
|
await interop.RedirectBrowser(NavigateUrl(), 10);
|
||||||
await InstallationService.Upgrade();
|
await InstallationService.Upgrade(bool.Parse(_backup));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -102,6 +130,7 @@
|
|||||||
ShowProgressIndicator();
|
ShowProgressIndicator();
|
||||||
await PackageService.DownloadPackageAsync(packageid, version);
|
await PackageService.DownloadPackageAsync(packageid, version);
|
||||||
await PackageService.DownloadPackageAsync(Constants.UpdaterPackageId, version);
|
await PackageService.DownloadPackageAsync(Constants.UpdaterPackageId, version);
|
||||||
|
_downloaded = true;
|
||||||
HideProgressIndicator();
|
HideProgressIndicator();
|
||||||
AddModuleMessage(Localizer["Success.Framework.Download"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.Framework.Download"], MessageType.Success);
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,16 @@
|
|||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="url" HelpText="The fully qualified Url for this site" ResourceKey="Url">Url:</Label>
|
<Label Class="col-sm-3" For="url" HelpText="A Url identifying a path to a specific page in the site (absolute or relative)" ResourceKey="Url">Url:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="url" class="form-control" @bind="@_url" maxlength="500" required />
|
<div class="input-group">
|
||||||
|
<input id="url" class="form-control" @bind="@_url" maxlength="500" required />
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="GenerateUrl">@Localizer["Generate"]</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="mappedurl" HelpText="A fully qualified Url where the user will be redirected" ResourceKey="MappedUrl">Redirect To:</Label>
|
<Label Class="col-sm-3" For="mappedurl" HelpText="A Url where the user will be redirected (absolute or relative). Use '/' for site root path." ResourceKey="MappedUrl">Redirect To:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="mappedurl" class="form-control" @bind="@_mappedurl" maxlength="500" required />
|
<input id="mappedurl" class="form-control" @bind="@_mappedurl" maxlength="500" required />
|
||||||
</div>
|
</div>
|
||||||
@ -26,64 +29,80 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
|
|
||||||
private string _url = string.Empty;
|
private string _url = string.Empty;
|
||||||
private string _mappedurl = string.Empty;
|
private string _mappedurl = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
private async Task SaveUrlMapping()
|
private async Task SaveUrlMapping()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
if (await interop.FormValid(form))
|
if (await interop.FormValid(form))
|
||||||
{
|
{
|
||||||
if (_url != _mappedurl)
|
if (_url != _mappedurl)
|
||||||
{
|
{
|
||||||
var url = PageState.Uri.Scheme + "://" + PageState.Uri.Authority + "/";
|
var url = PageState.Uri.Scheme + "://" + PageState.Uri.Authority + "/";
|
||||||
url = url + (!string.IsNullOrEmpty(PageState.Alias.Path) ? PageState.Alias.Path + "/" : "");
|
url = url + (!string.IsNullOrEmpty(PageState.Alias.Path) ? PageState.Alias.Path + "/" : "");
|
||||||
|
|
||||||
_url = (_url.StartsWith("/")) ? _url.Substring(1) : _url;
|
_url = (_url.StartsWith("/")) ? _url.Substring(1) : _url;
|
||||||
_url = (!_url.StartsWith("http")) ? url + _url : _url;
|
_url = (!_url.StartsWith("http")) ? url + _url : _url;
|
||||||
|
|
||||||
if (_url.StartsWith(url))
|
_mappedurl = _mappedurl.Replace(url, "");
|
||||||
{
|
_mappedurl = (_mappedurl.StartsWith("/") && _mappedurl != "/") ? _mappedurl.Substring(1) : _mappedurl;
|
||||||
var urlmapping = new UrlMapping();
|
|
||||||
urlmapping.SiteId = PageState.Site.SiteId;
|
|
||||||
var route = new Route(_url, PageState.Alias.Path);
|
|
||||||
urlmapping.Url = route.PagePath;
|
|
||||||
urlmapping.MappedUrl = _mappedurl.Replace(url, "");
|
|
||||||
urlmapping.Requests = 0;
|
|
||||||
urlmapping.CreatedOn = DateTime.UtcNow;
|
|
||||||
urlmapping.RequestedOn = DateTime.UtcNow;
|
|
||||||
|
|
||||||
try
|
if (_url.StartsWith(url))
|
||||||
{
|
{
|
||||||
urlmapping = await UrlMappingService.AddUrlMappingAsync(urlmapping);
|
var urlmapping = new UrlMapping();
|
||||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
urlmapping.SiteId = PageState.Site.SiteId;
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
urlmapping.Url = new Route(_url, PageState.Alias.Path).PagePath;
|
||||||
}
|
urlmapping.MappedUrl = _mappedurl;
|
||||||
catch (Exception ex)
|
urlmapping.Requests = 0;
|
||||||
{
|
urlmapping.CreatedOn = DateTime.UtcNow;
|
||||||
await logger.LogError(ex, "Error Saving UrlMapping {UrlMapping} {Error}", urlmapping, ex.Message);
|
urlmapping.RequestedOn = DateTime.UtcNow;
|
||||||
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
|
||||||
}
|
try
|
||||||
}
|
{
|
||||||
else
|
urlmapping = await UrlMappingService.AddUrlMappingAsync(urlmapping);
|
||||||
{
|
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||||
AddModuleMessage(Localizer["Message.SaveUrlMapping"], MessageType.Warning);
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
else
|
{
|
||||||
{
|
await logger.LogError(ex, "Error Saving UrlMapping {UrlMapping} {Error}", urlmapping, ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.SaveUrlMapping"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
AddModuleMessage(Localizer["Message.DuplicateUrlMapping"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.DuplicateUrlMapping"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GenerateUrl()
|
||||||
|
{
|
||||||
|
var url = PageState.Uri.Scheme + "://" + PageState.Uri.Authority + "/";
|
||||||
|
url = url + (!string.IsNullOrEmpty(PageState.Alias.Path) ? PageState.Alias.Path + "/" : "");
|
||||||
|
|
||||||
|
var chars = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
Random rnd = new Random();
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
url += chars.Substring(rnd.Next(0, chars.Length - 1), 1);
|
||||||
|
}
|
||||||
|
_url = url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,13 @@
|
|||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="url" HelpText="A fully qualified Url for this site" ResourceKey="Url">Url:</Label>
|
<Label Class="col-sm-3" For="url" HelpText="A Url identifying a path to a specific page in the site (absolute or relative)" ResourceKey="Url">Url:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="url" class="form-control" @bind="@_url" maxlength="500" readonly />
|
<input id="url" class="form-control" @bind="@_url" maxlength="500" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="mappedurl" HelpText="A fully qualified Url where the user will be redirected" ResourceKey="MappedUrl">Redirect To:</Label>
|
<Label Class="col-sm-3" For="mappedurl" HelpText="A Url where the user will be redirected (absolute or relative). Use '/' for site root path." ResourceKey="MappedUrl">Redirect To:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="mappedurl" class="form-control" @bind="@_mappedurl" maxlength="500" required />
|
<input id="mappedurl" class="form-control" @bind="@_mappedurl" maxlength="500" required />
|
||||||
</div>
|
</div>
|
||||||
@ -67,8 +67,11 @@
|
|||||||
var url = PageState.Uri.Scheme + "://" + PageState.Uri.Authority + "/";
|
var url = PageState.Uri.Scheme + "://" + PageState.Uri.Authority + "/";
|
||||||
url = url + (!string.IsNullOrEmpty(PageState.Alias.Path) ? PageState.Alias.Path + "/" : "");
|
url = url + (!string.IsNullOrEmpty(PageState.Alias.Path) ? PageState.Alias.Path + "/" : "");
|
||||||
|
|
||||||
|
_mappedurl = _mappedurl.Replace(url, "");
|
||||||
|
_mappedurl = (_mappedurl.StartsWith("/") && _mappedurl != "/") ? _mappedurl.Substring(1) : _mappedurl;
|
||||||
|
|
||||||
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
||||||
urlmapping.MappedUrl = _mappedurl.Replace(url, "");
|
urlmapping.MappedUrl = _mappedurl;
|
||||||
urlmapping = await UrlMappingService.UpdateUrlMappingAsync(urlmapping);
|
urlmapping = await UrlMappingService.UpdateUrlMappingAsync(urlmapping);
|
||||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IUrlMappingService UrlMappingService
|
@inject IUrlMappingService UrlMappingService
|
||||||
@inject ISiteService SiteService
|
@inject ISiteService SiteService
|
||||||
|
@inject ISettingService SettingService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ else
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>@context.Requests</td>
|
<td>@context.Requests</td>
|
||||||
<td>@context.RequestedOn</td>
|
<td>@UtcToLocal(context.RequestedOn)</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@ -62,7 +63,13 @@ else
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="retention" HelpText="Number of days of broken urls to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@ -73,6 +80,7 @@ else
|
|||||||
private bool _mapped = true;
|
private bool _mapped = true;
|
||||||
private List<UrlMapping> _urlMappings;
|
private List<UrlMapping> _urlMappings;
|
||||||
private string _capturebrokenurls;
|
private string _capturebrokenurls;
|
||||||
|
private int _retention = 30;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
@ -80,7 +88,10 @@ else
|
|||||||
{
|
{
|
||||||
await GetUrlMappings();
|
await GetUrlMappings();
|
||||||
_capturebrokenurls = PageState.Site.CaptureBrokenUrls.ToString();
|
_capturebrokenurls = PageState.Site.CaptureBrokenUrls.ToString();
|
||||||
}
|
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
_retention = int.Parse(SettingService.GetSetting(settings, "UrlMappingRetention", "30"));
|
||||||
|
}
|
||||||
|
|
||||||
private async void MappedChanged(ChangeEventArgs e)
|
private async void MappedChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
@ -124,7 +135,12 @@ else
|
|||||||
var site = PageState.Site;
|
var site = PageState.Site;
|
||||||
site.CaptureBrokenUrls = bool.Parse(_capturebrokenurls);
|
site.CaptureBrokenUrls = bool.Parse(_capturebrokenurls);
|
||||||
await SiteService.UpdateSiteAsync(site);
|
await SiteService.UpdateSiteAsync(site);
|
||||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||||
|
settings = SettingService.SetSetting(settings, "UrlMappingRetention", _retention.ToString(), true);
|
||||||
|
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||||
|
|
||||||
|
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
@inject INotificationService NotificationService
|
@inject INotificationService NotificationService
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@inject IFolderService FolderService
|
@inject IFolderService FolderService
|
||||||
|
@inject ITimeZoneService TimeZoneService
|
||||||
@inject IJSRuntime jsRuntime
|
@inject IJSRuntime jsRuntime
|
||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@ -16,9 +17,9 @@
|
|||||||
|
|
||||||
@if (_initialized)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
@if (PageState.User != null && photo != null)
|
@if (PageState.User != null && _photo != null)
|
||||||
{
|
{
|
||||||
<img src="@ImageUrl(photofileid, 400, 400)" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
<img src="@ImageUrl(_photofileid, 400, 400)" alt="@_displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -31,7 +32,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="username" HelpText="Your username. Note that this field can not be modified." ResourceKey="Username"></Label>
|
<Label Class="col-sm-3" For="username" HelpText="Your username. Note that this field can not be modified." ResourceKey="Username"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="username" class="form-control" @bind="@username" readonly />
|
<input id="username" class="form-control" @bind="@_username" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -47,17 +48,17 @@
|
|||||||
<Label Class="col-sm-3" For="confirm" HelpText="If you are changing your password you must enter it again to confirm it matches" ResourceKey="Confirm"></Label>
|
<Label Class="col-sm-3" For="confirm" HelpText="If you are changing your password you must enter it again to confirm it matches" ResourceKey="Confirm"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
|
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (allowtwofactor)
|
@if (_allowtwofactor)
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="twofactor" HelpText="Indicates if you are using two factor authentication. Two factor authentication requires you to enter a verification code sent via email after you sign in." ResourceKey="TwoFactor"></Label>
|
<Label Class="col-sm-3" For="twofactor" HelpText="Indicates if you are using two factor authentication. Two factor authentication requires you to enter a verification code sent via email after you sign in." ResourceKey="TwoFactor"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="twofactor" class="form-select" @bind="@twofactor" required>
|
<select id="twofactor" class="form-select" @bind="@_twofactor" required>
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
@ -67,19 +68,31 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to receive notifications" ResourceKey="Email"></Label>
|
<Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to receive notifications" ResourceKey="Email"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="email" class="form-control" @bind="@email" />
|
<input id="email" class="form-control" @bind="@_email" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="displayname" HelpText="Your full name" ResourceKey="DisplayName"></Label>
|
<Label Class="col-sm-3" For="displayname" HelpText="Your full name" ResourceKey="DisplayName"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="displayname" class="form-control" @bind="@displayname" />
|
<input id="displayname" class="form-control" @bind="@_displayname" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="@photofileid.ToString()" HelpText="A photo of yourself" ResourceKey="Photo"></Label>
|
<Label Class="col-sm-3" For="timezone" HelpText="Your time zone" ResourceKey="TimeZone">Time Zone:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<FileManager FileId="@photofileid" Filter="@PageState.Site.ImageFiles" ShowFolders="false" ShowFiles="true" UploadMultiple="false" FolderId="@folderid" @ref="filemanager" />
|
<select id="timezone" class="form-select" @bind="@_timezoneid">
|
||||||
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var timezone in _timezones)
|
||||||
|
{
|
||||||
|
<option value="@timezone.Id">@timezone.DisplayName</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="@_photofileid.ToString()" HelpText="A photo of yourself" ResourceKey="Photo"></Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<FileManager FileId="@_photofileid" Filter="@PageState.Site.ImageFiles" ShowFolders="false" ShowFiles="true" UploadMultiple="false" FolderId="@_folderid" @ref="_filemanager" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -91,21 +104,21 @@
|
|||||||
<TabPanel Name="Profile" ResourceKey="Profile">
|
<TabPanel Name="Profile" ResourceKey="Profile">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@foreach (Profile profile in profiles)
|
@foreach (Profile profile in _profiles)
|
||||||
{
|
{
|
||||||
var p = profile;
|
var p = profile;
|
||||||
if (!p.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
if (!p.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
if (p.Category != category)
|
if (p.Category != _category)
|
||||||
{
|
{
|
||||||
<div class="col text-center pb-2">
|
<div class="col text-center pb-2">
|
||||||
@p.Category
|
@p.Category
|
||||||
</div>
|
</div>
|
||||||
category = p.Category;
|
_category = p.Category;
|
||||||
}
|
}
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@if (!string.IsNullOrEmpty(p.Options))
|
@if (!string.IsNullOrEmpty(p.Options))
|
||||||
{
|
{
|
||||||
@if (!string.IsNullOrEmpty(p.Autocomplete))
|
@if (!string.IsNullOrEmpty(p.Autocomplete))
|
||||||
@ -149,22 +162,26 @@
|
|||||||
{
|
{
|
||||||
@if (p.IsRequired)
|
@if (p.IsRequired)
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete" />
|
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"
|
||||||
|
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete" />
|
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"
|
||||||
|
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@if (p.IsRequired)
|
@if (p.IsRequired)
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))"
|
||||||
|
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"
|
||||||
|
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,22 +191,26 @@
|
|||||||
{
|
{
|
||||||
@if (p.IsRequired)
|
@if (p.IsRequired)
|
||||||
{
|
{
|
||||||
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"></textarea>
|
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"
|
||||||
|
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"></textarea>
|
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"
|
||||||
|
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@if (p.IsRequired)
|
@if (p.IsRequired)
|
||||||
{
|
{
|
||||||
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))"
|
||||||
|
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"
|
||||||
|
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,17 +233,17 @@
|
|||||||
<option value="from">@Localizer["Items.Sent"]</option>
|
<option value="from">@Localizer["Items.Sent"]</option>
|
||||||
</select>
|
</select>
|
||||||
<br />
|
<br />
|
||||||
@if (filter == "to")
|
@if (_filter == "to")
|
||||||
{
|
{
|
||||||
@if (notifications.Any())
|
@if (_notifications.Any())
|
||||||
{
|
{
|
||||||
<Pager Items="@notifications">
|
<Pager Items="@_notifications">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@Localizer["From"]</th>
|
<th>@Localizer["From"]</th>
|
||||||
<th>@Localizer["Subject"]</th>
|
<th>@Localizer["Subject"]</th>
|
||||||
<th>@Localizer["Received"]</th>
|
<th>@Localizer["Received"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" /></td>
|
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" /></td>
|
||||||
@ -230,13 +251,13 @@
|
|||||||
|
|
||||||
@if (context.IsRead)
|
@if (context.IsRead)
|
||||||
{
|
{
|
||||||
<td>@context.FromDisplayName</td>
|
<td>@(string.IsNullOrEmpty(context.FromDisplayName) ? SharedLocalizer["System"] : context.FromDisplayName)</td>
|
||||||
<td>@context.Subject</td>
|
<td>@context.Subject</td>
|
||||||
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
|
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<td><b>@context.FromDisplayName</b></td>
|
<td><b>@(string.IsNullOrEmpty(context.FromDisplayName) ? SharedLocalizer["System"] : context.FromDisplayName)</b></td>
|
||||||
<td><b>@context.Subject</b></td>
|
<td><b>@context.Subject</b></td>
|
||||||
<td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
|
<td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
|
||||||
}
|
}
|
||||||
@ -252,15 +273,15 @@
|
|||||||
context.Body = context.Body.Replace("\n", "");
|
context.Body = context.Body.Replace("\n", "");
|
||||||
context.Body = context.Body.Replace("\r", "");
|
context.Body = context.Body.Replace("\r", "");
|
||||||
}
|
}
|
||||||
notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
|
_notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
|
||||||
}
|
}
|
||||||
@if (context.IsRead)
|
@if (context.IsRead)
|
||||||
{
|
{
|
||||||
@notificationSummary
|
@_notificationSummary
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<b>@notificationSummary</b>
|
<b>@_notificationSummary</b>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
</Detail>
|
</Detail>
|
||||||
@ -277,15 +298,15 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@if (notifications.Any())
|
@if (_notifications.Any())
|
||||||
{
|
{
|
||||||
<Pager Items="@notifications">
|
<Pager Items="@_notifications">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"></th>
|
<th style="width: 1px;"></th>
|
||||||
<th style="width: 1px;"></th>
|
<th style="width: 1px;"></th>
|
||||||
<th>@Localizer["To"]</th>
|
<th>@Localizer["To"]</th>
|
||||||
<th>@Localizer["Subject"]</th>
|
<th>@Localizer["Subject"]</th>
|
||||||
<th>@Localizer["Sent"]</th>
|
<th>@Localizer["Sent"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" /></td>
|
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" /></td>
|
||||||
@ -316,15 +337,15 @@
|
|||||||
context.Body = context.Body.Replace("\n", "");
|
context.Body = context.Body.Replace("\n", "");
|
||||||
context.Body = context.Body.Replace("\r", "");
|
context.Body = context.Body.Replace("\r", "");
|
||||||
}
|
}
|
||||||
notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
|
_notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
|
||||||
}
|
}
|
||||||
@if (context.IsRead)
|
@if (context.IsRead)
|
||||||
{
|
{
|
||||||
@notificationSummary
|
@_notificationSummary
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<b>@notificationSummary</b>
|
<b>@_notificationSummary</b>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
</Detail>
|
</Detail>
|
||||||
@ -346,29 +367,32 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private List<Models.TimeZone> _timezones;
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private string _passwordrequirements;
|
private string _passwordrequirements;
|
||||||
private string username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private string _password = string.Empty;
|
private string _password = string.Empty;
|
||||||
private string _passwordtype = "password";
|
private string _passwordtype = "password";
|
||||||
private string _togglepassword = string.Empty;
|
private string _togglepassword = string.Empty;
|
||||||
private string confirm = string.Empty;
|
private string _confirm = string.Empty;
|
||||||
private bool allowtwofactor = false;
|
private bool _allowtwofactor = false;
|
||||||
private string twofactor = "False";
|
private string _twofactor = "False";
|
||||||
private string email = string.Empty;
|
private string _email = string.Empty;
|
||||||
private string displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
private FileManager filemanager;
|
private FileManager _filemanager;
|
||||||
private int folderid = -1;
|
private int _folderid = -1;
|
||||||
private int photofileid = -1;
|
private string _timezoneid = string.Empty;
|
||||||
private File photo = null;
|
private int _photofileid = -1;
|
||||||
private string _ImageFiles = string.Empty;
|
private File _photo = null;
|
||||||
private List<Profile> profiles;
|
private string _imagefiles = string.Empty;
|
||||||
private Dictionary<string, string> settings;
|
|
||||||
private string category = string.Empty;
|
|
||||||
|
|
||||||
private string filter = "to";
|
private List<Profile> _profiles;
|
||||||
private List<Notification> notifications;
|
private Dictionary<string, string> _userSettings;
|
||||||
private string notificationSummary = string.Empty;
|
private string _category = string.Empty;
|
||||||
|
|
||||||
|
private string _filter = "to";
|
||||||
|
private List<Notification> _notifications;
|
||||||
|
private string _notificationSummary = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||||
|
|
||||||
@ -378,17 +402,19 @@
|
|||||||
{
|
{
|
||||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true");
|
_allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true");
|
||||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||||
|
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||||
|
|
||||||
if (PageState.User != null)
|
if (PageState.User != null)
|
||||||
{
|
{
|
||||||
username = PageState.User.Username;
|
_username = PageState.User.Username;
|
||||||
twofactor = PageState.User.TwoFactorRequired.ToString();
|
_twofactor = PageState.User.TwoFactorRequired.ToString();
|
||||||
email = PageState.User.Email;
|
_email = PageState.User.Email;
|
||||||
displayname = PageState.User.DisplayName;
|
_displayname = PageState.User.DisplayName;
|
||||||
|
_timezoneid = PageState.User.TimeZoneId;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(email))
|
if (string.IsNullOrEmpty(_email))
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.User.NoEmail"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.User.NoEmail"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
@ -397,24 +423,24 @@
|
|||||||
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
{
|
{
|
||||||
folderid = folder.FolderId;
|
_folderid = folder.FolderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageState.User.PhotoFileId != null)
|
if (PageState.User.PhotoFileId != null)
|
||||||
{
|
{
|
||||||
photofileid = PageState.User.PhotoFileId.Value;
|
_photofileid = PageState.User.PhotoFileId.Value;
|
||||||
photo = await FileService.GetFileAsync(photofileid);
|
_photo = await FileService.GetFileAsync(_photofileid);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
photofileid = -1;
|
_photofileid = -1;
|
||||||
photo = null;
|
_photo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
_userSettings = PageState.User.Settings;
|
||||||
var sitesettings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
var sitesettings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
_ImageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles);
|
_imagefiles = SettingService.GetSetting(_userSettings, "ImageFiles", Constants.ImageFiles);
|
||||||
_ImageFiles = (string.IsNullOrEmpty(_ImageFiles)) ? Constants.ImageFiles : _ImageFiles;
|
_imagefiles = (string.IsNullOrEmpty(_imagefiles)) ? Constants.ImageFiles : _imagefiles;
|
||||||
|
|
||||||
await LoadNotificationsAsync();
|
await LoadNotificationsAsync();
|
||||||
|
|
||||||
@ -434,13 +460,13 @@
|
|||||||
|
|
||||||
private async Task LoadNotificationsAsync()
|
private async Task LoadNotificationsAsync()
|
||||||
{
|
{
|
||||||
notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
|
_notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, _filter, PageState.User.UserId);
|
||||||
notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
|
_notifications = _notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||||
{
|
{
|
||||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
string value = SettingService.GetSetting(_userSettings, SettingName, DefaultValue);
|
||||||
if (value.Contains("]"))
|
if (value.Contains("]"))
|
||||||
{
|
{
|
||||||
value = value.Substring(value.IndexOf("]") + 1);
|
value = value.Substring(value.IndexOf("]") + 1);
|
||||||
@ -452,38 +478,39 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (username != string.Empty && email != string.Empty)
|
if (_username != string.Empty && _email != string.Empty)
|
||||||
{
|
{
|
||||||
if (_password == confirm)
|
if (_password == _confirm)
|
||||||
{
|
{
|
||||||
if (ValidateProfiles())
|
if (ValidateProfiles())
|
||||||
{
|
{
|
||||||
var user = PageState.User;
|
var user = PageState.User;
|
||||||
user.Username = username;
|
user.Username = _username;
|
||||||
user.Password = _password;
|
user.Password = _password;
|
||||||
user.TwoFactorRequired = bool.Parse(twofactor);
|
user.TwoFactorRequired = bool.Parse(_twofactor);
|
||||||
user.Email = email;
|
user.Email = _email;
|
||||||
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
user.DisplayName = (_displayname == string.Empty ? _username : _displayname);
|
||||||
user.PhotoFileId = filemanager.GetFileId();
|
user.TimeZoneId = _timezoneid;
|
||||||
|
user.PhotoFileId = _filemanager.GetFileId();
|
||||||
if (user.PhotoFileId == -1)
|
if (user.PhotoFileId == -1)
|
||||||
{
|
{
|
||||||
user.PhotoFileId = null;
|
user.PhotoFileId = null;
|
||||||
}
|
}
|
||||||
if (user.PhotoFileId != null)
|
if (user.PhotoFileId != null)
|
||||||
{
|
{
|
||||||
photofileid = user.PhotoFileId.Value;
|
_photofileid = user.PhotoFileId.Value;
|
||||||
photo = await FileService.GetFileAsync(photofileid);
|
_photo = await FileService.GetFileAsync(_photofileid);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
photofileid = -1;
|
_photofileid = -1;
|
||||||
photo = null;
|
_photo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
user = await UserService.UpdateUserAsync(user);
|
user = await UserService.UpdateUserAsync(user);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
await SettingService.UpdateUserSettingsAsync(_userSettings, PageState.User.UserId);
|
||||||
await logger.LogInformation("User Profile Saved");
|
await logger.LogInformation("User Profile Saved");
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||||
@ -549,12 +576,12 @@
|
|||||||
|
|
||||||
private bool ValidateProfiles()
|
private bool ValidateProfiles()
|
||||||
{
|
{
|
||||||
foreach (Profile profile in profiles)
|
foreach (Profile profile in _profiles)
|
||||||
{
|
{
|
||||||
var value = GetProfileValue(profile.Name, string.Empty);
|
var value = GetProfileValue(profile.Name, string.Empty);
|
||||||
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
|
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
|
||||||
{
|
{
|
||||||
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
|
_userSettings = SettingService.SetSetting(_userSettings, profile.Name, profile.DefaultValue);
|
||||||
}
|
}
|
||||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
@ -586,7 +613,7 @@
|
|||||||
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
||||||
{
|
{
|
||||||
var value = (string)e.Value;
|
var value = (string)e.Value;
|
||||||
settings = SettingService.SetSetting(settings, SettingName, value);
|
_userSettings = SettingService.SetSetting(_userSettings, SettingName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Delete(Notification Notification)
|
private async Task Delete(Notification Notification)
|
||||||
@ -616,7 +643,7 @@
|
|||||||
|
|
||||||
private async void FilterChanged(ChangeEventArgs e)
|
private async void FilterChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
filter = (string)e.Value;
|
_filter = (string)e.Value;
|
||||||
await LoadNotificationsAsync();
|
await LoadNotificationsAsync();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
@ -626,7 +653,7 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ShowProgressIndicator();
|
ShowProgressIndicator();
|
||||||
foreach(var Notification in notifications)
|
foreach(var Notification in _notifications)
|
||||||
{
|
{
|
||||||
if (!Notification.IsDeleted)
|
if (!Notification.IsDeleted)
|
||||||
{
|
{
|
||||||
|
@ -128,7 +128,7 @@
|
|||||||
createdon = notification.CreatedOn.ToString();
|
createdon = notification.CreatedOn.ToString();
|
||||||
body = notification.Body;
|
body = notification.Body;
|
||||||
|
|
||||||
if (title == "From")
|
if (title == "From" && !notification.IsRead)
|
||||||
{
|
{
|
||||||
notification.IsRead = true;
|
notification.IsRead = true;
|
||||||
notification = await NotificationService.UpdateNotificationAsync(notification);
|
notification = await NotificationService.UpdateNotificationAsync(notification);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
@inject IProfileService ProfileService
|
@inject IProfileService ProfileService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
@inject ITimeZoneService TimeZoneService
|
||||||
@inject IStringLocalizer<Add> Localizer
|
@inject IStringLocalizer<Add> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@ -12,7 +13,7 @@
|
|||||||
{
|
{
|
||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Identity" ResourceKey="Identity">
|
<TabPanel Name="Identity" ResourceKey="Identity">
|
||||||
@if (profiles != null)
|
@if (_profiles != null)
|
||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -33,6 +34,18 @@
|
|||||||
<input id="displayname" class="form-control" @bind="@_displayname" />
|
<input id="displayname" class="form-control" @bind="@_displayname" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="timezone" HelpText="Your time zone" ResourceKey="TimeZone">Time Zone:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="timezone" class="form-select" @bind="@_timezoneid">
|
||||||
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var timezone in _timezones)
|
||||||
|
{
|
||||||
|
<option value="@timezone.Id">@timezone.DisplayName</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="notify" HelpText="Indicate if new users should receive an email notification" ResourceKey="Notify">Notify? </Label>
|
<Label Class="col-sm-3" For="notify" HelpText="Indicate if new users should receive an email notification" ResourceKey="Notify">Notify? </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -48,20 +61,20 @@
|
|||||||
<TabPanel Name="Profile" ResourceKey="Profile">
|
<TabPanel Name="Profile" ResourceKey="Profile">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@foreach (Profile profile in profiles)
|
@foreach (Profile profile in _profiles)
|
||||||
{
|
{
|
||||||
var p = profile;
|
var p = profile;
|
||||||
if (p.Category != category)
|
if (p.Category != _category)
|
||||||
{
|
{
|
||||||
<div class="col text-center pb-2">
|
<div class="col text-center pb-2">
|
||||||
<strong>@p.Category</strong>
|
<strong>@p.Category</strong>
|
||||||
</div>
|
</div>
|
||||||
category = p.Category;
|
_category = p.Category;
|
||||||
}
|
}
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@if (!string.IsNullOrEmpty(p.Options))
|
@if (!string.IsNullOrEmpty(p.Options))
|
||||||
{
|
{
|
||||||
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
|
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
|
||||||
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
@ -81,11 +94,11 @@
|
|||||||
{
|
{
|
||||||
@if (p.Rows == 1)
|
@if (p.Rows == 1)
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@ -103,14 +116,16 @@
|
|||||||
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private List<Models.TimeZone> _timezones;
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private string _email = string.Empty;
|
private string _email = string.Empty;
|
||||||
private string _displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
|
private string _timezoneid = string.Empty;
|
||||||
private string _notify = "True";
|
private string _notify = "True";
|
||||||
private List<Profile> profiles;
|
private List<Profile> _profiles;
|
||||||
private Dictionary<string, string> settings;
|
private Dictionary<string, string> _settings;
|
||||||
private string category = string.Empty;
|
private string _category = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
@ -118,8 +133,10 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||||
settings = new Dictionary<string, string>();
|
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||||
|
_settings = new Dictionary<string, string>();
|
||||||
|
_timezoneid = PageState.Site.TimeZoneId;
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -131,7 +148,7 @@
|
|||||||
|
|
||||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||||
{
|
{
|
||||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
string value = SettingService.GetSetting(_settings, SettingName, DefaultValue);
|
||||||
if (value.Contains("]"))
|
if (value.Contains("]"))
|
||||||
{
|
{
|
||||||
value = value.Substring(value.IndexOf("]") + 1);
|
value = value.Substring(value.IndexOf("]") + 1);
|
||||||
@ -153,6 +170,7 @@
|
|||||||
user.Password = ""; // will be auto generated
|
user.Password = ""; // will be auto generated
|
||||||
user.Email = _email;
|
user.Email = _email;
|
||||||
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
||||||
|
user.TimeZoneId = _timezoneid;
|
||||||
user.PhotoFileId = null;
|
user.PhotoFileId = null;
|
||||||
user.SuppressNotification = !bool.Parse(_notify);
|
user.SuppressNotification = !bool.Parse(_notify);
|
||||||
|
|
||||||
@ -160,7 +178,7 @@
|
|||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
await SettingService.UpdateUserSettingsAsync(_settings, user.UserId);
|
||||||
await logger.LogInformation("User Created {User}", user);
|
await logger.LogInformation("User Created {User}", user);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
@ -185,12 +203,12 @@
|
|||||||
|
|
||||||
private bool ValidateProfiles()
|
private bool ValidateProfiles()
|
||||||
{
|
{
|
||||||
foreach (Profile profile in profiles)
|
foreach (Profile profile in _profiles)
|
||||||
{
|
{
|
||||||
var value = GetProfileValue(profile.Name, string.Empty);
|
var value = GetProfileValue(profile.Name, string.Empty);
|
||||||
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
|
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
|
||||||
{
|
{
|
||||||
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
|
_settings = SettingService.SetSetting(_settings, profile.Name, profile.DefaultValue);
|
||||||
}
|
}
|
||||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
@ -217,6 +235,6 @@
|
|||||||
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
||||||
{
|
{
|
||||||
var value = (string)e.Value;
|
var value = (string)e.Value;
|
||||||
settings = SettingService.SetSetting(settings, SettingName, value);
|
_settings = SettingService.SetSetting(_settings, SettingName, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
@inject IProfileService ProfileService
|
@inject IProfileService ProfileService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
|
@inject ITimeZoneService TimeZoneService
|
||||||
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Edit> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@ -16,13 +18,13 @@
|
|||||||
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="username" HelpText="The unique username for a user. Note that this field can not be modified." ResourceKey="Username"></Label>
|
<Label Class="col-sm-3" For="username" HelpText="The unique username for a user. Note that this field can not be modified." ResourceKey="Username">Username:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="username" class="form-control" @bind="@username" readonly />
|
<input id="username" class="form-control" @bind="@_username" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password"></Label>
|
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password">Password:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
|
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
|
||||||
@ -31,45 +33,69 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm"></Label>
|
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm">Confirm Password:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
|
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="email" HelpText="The email address where the user will receive notifications" ResourceKey="Email"></Label>
|
<Label Class="col-sm-3" For="email" HelpText="The email address where the user will receive notifications" ResourceKey="Email">Email:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="email" class="form-control" @bind="@email" />
|
<input id="email" class="form-control" @bind="@_email" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
|
<Label Class="col-sm-3" For="confirmed" HelpText="Indicates if the user's email is verified" ResourceKey="Confirmed">Confirmed?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="displayname" class="form-control" @bind="@displayname" />
|
<select id="confirmed" class="form-select" @bind="@_confirmed">
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="isdeleted" HelpText="Indicate if the user is active" ResourceKey="IsDeleted"></Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="isdeleted" class="form-select" @bind="@isdeleted">
|
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="lastlogin" HelpText="The date and time when the user last signed in" ResourceKey="LastLogin"></Label>
|
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName">Full Name:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="lastlogin" class="form-control" @bind="@lastlogin" readonly />
|
<input id="displayname" class="form-control" @bind="@_displayname" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="lastipaddress" HelpText="The IP Address of the user recorded during their last login" ResourceKey="LastIPAddress"></Label>
|
<Label Class="col-sm-3" For="timezone" HelpText="Your time zone" ResourceKey="TimeZone">Time Zone:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="lastipaddress" class="form-control" @bind="@lastipaddress" readonly />
|
<select id="timezone" class="form-select" @bind="@_timezoneid">
|
||||||
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var timezone in _timezones)
|
||||||
|
{
|
||||||
|
<option value="@timezone.Id">@timezone.DisplayName</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="isdeleted" HelpText="Indicate if the user is active" ResourceKey="IsDeleted">Deleted?</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="isdeleted" class="form-select" @bind="@_isdeleted">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="lastlogin" HelpText="The date and time when the user last signed in" ResourceKey="LastLogin">Last Login:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="lastlogin" class="form-control" @bind="@_lastlogin" readonly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="lastipaddress" HelpText="The IP Address of the user recorded during their last login" ResourceKey="LastIPAddress">Last IP Address:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="lastipaddress" class="form-control" @bind="@_lastipaddress" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -77,20 +103,20 @@
|
|||||||
<TabPanel Name="Profile" ResourceKey="Profile">
|
<TabPanel Name="Profile" ResourceKey="Profile">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@foreach (Profile profile in profiles)
|
@foreach (Profile profile in _profiles)
|
||||||
{
|
{
|
||||||
var p = profile;
|
var p = profile;
|
||||||
if (p.Category != category)
|
if (p.Category != _category)
|
||||||
{
|
{
|
||||||
<div class="col text-center pb-2">
|
<div class="col text-center pb-2">
|
||||||
<strong>@p.Category</strong>
|
<strong>@p.Category</strong>
|
||||||
</div>
|
</div>
|
||||||
category = p.Category;
|
_category = p.Category;
|
||||||
}
|
}
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@if (!string.IsNullOrEmpty(p.Options))
|
@if (!string.IsNullOrEmpty(p.Options))
|
||||||
{
|
{
|
||||||
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
|
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
|
||||||
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
@ -110,11 +136,11 @@
|
|||||||
{
|
{
|
||||||
@if (p.Rows == 1)
|
@if (p.Rows == 1)
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@ -124,39 +150,50 @@
|
|||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
<br />
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin) && PageState.Runtime != Shared.Runtime.Hybrid && !_ishost)
|
||||||
<br />
|
{
|
||||||
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
|
<button type="button" class="btn btn-primary ms-1" @onclick="ImpersonateUser">@Localizer["Impersonate"]</button>
|
||||||
|
}
|
||||||
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && _isdeleted == "True")
|
||||||
|
{
|
||||||
|
<ActionDialog Header="Delete User" Message="Are You Sure You Wish To Permanently Delete This User?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteUser())" ResourceKey="DeleteUser" />
|
||||||
|
}
|
||||||
|
<br /><br />
|
||||||
|
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private List<Models.TimeZone> _timezones;
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private string _passwordrequirements;
|
private string _passwordrequirements;
|
||||||
private int userid;
|
private int _userid;
|
||||||
private string username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private string _password = string.Empty;
|
private string _password = string.Empty;
|
||||||
private string _passwordtype = "password";
|
private string _passwordtype = "password";
|
||||||
private string _togglepassword = string.Empty;
|
private string _togglepassword = string.Empty;
|
||||||
private string confirm = string.Empty;
|
private string _confirm = string.Empty;
|
||||||
private string email = string.Empty;
|
private string _email = string.Empty;
|
||||||
private string displayname = string.Empty;
|
private string _confirmed = string.Empty;
|
||||||
private string isdeleted;
|
private string _displayname = string.Empty;
|
||||||
private string lastlogin;
|
private string _timezoneid = string.Empty;
|
||||||
private string lastipaddress;
|
private string _isdeleted;
|
||||||
|
private string _lastlogin;
|
||||||
|
private string _lastipaddress;
|
||||||
|
private bool _ishost = false;
|
||||||
|
|
||||||
private List<Profile> profiles;
|
private List<Profile> _profiles;
|
||||||
private Dictionary<string, string> settings;
|
private Dictionary<string, string> _settings;
|
||||||
private string category = string.Empty;
|
private string _category = string.Empty;
|
||||||
|
|
||||||
private string createdby;
|
private string _createdby;
|
||||||
private DateTime createdon;
|
private DateTime _createdon;
|
||||||
private string modifiedby;
|
private string _modifiedby;
|
||||||
private DateTime modifiedon;
|
private DateTime _modifiedon;
|
||||||
private string deletedby;
|
private string _deletedby;
|
||||||
private DateTime? deletedon;
|
private DateTime? _deletedon;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
@ -166,28 +203,32 @@
|
|||||||
{
|
{
|
||||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
_profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
||||||
|
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int UserId))
|
if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int UserId))
|
||||||
{
|
{
|
||||||
userid = UserId;
|
_userid = UserId;
|
||||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
var user = await UserService.GetUserAsync(_userid, PageState.Site.SiteId);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
username = user.Username;
|
_username = user.Username;
|
||||||
email = user.Email;
|
_email = user.Email;
|
||||||
displayname = user.DisplayName;
|
_confirmed = user.EmailConfirmed.ToString();
|
||||||
isdeleted = user.IsDeleted.ToString();
|
_displayname = user.DisplayName;
|
||||||
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
|
_timezoneid = PageState.User.TimeZoneId;
|
||||||
lastipaddress = user.LastIPAddress;
|
_isdeleted = user.IsDeleted.ToString();
|
||||||
|
_lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", UtcToLocal(user.LastLoginOn));
|
||||||
|
_lastipaddress = user.LastIPAddress;
|
||||||
|
_ishost = UserSecurity.ContainsRole(user.Roles, RoleNames.Host);
|
||||||
|
|
||||||
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
_settings = user.Settings;
|
||||||
createdby = user.CreatedBy;
|
_createdby = user.CreatedBy;
|
||||||
createdon = user.CreatedOn;
|
_createdon = user.CreatedOn;
|
||||||
modifiedby = user.ModifiedBy;
|
_modifiedby = user.ModifiedBy;
|
||||||
modifiedon = user.ModifiedOn;
|
_modifiedon = user.ModifiedOn;
|
||||||
deletedby = user.DeletedBy;
|
_deletedby = user.DeletedBy;
|
||||||
deletedon = user.DeletedOn;
|
_deletedon = user.DeletedOn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,14 +236,14 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
|
await logger.LogError(ex, "Error Loading User {UserId} {Error}", _userid, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||||
{
|
{
|
||||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
string value = SettingService.GetSetting(_settings, SettingName, DefaultValue);
|
||||||
if (value.Contains("]"))
|
if (value.Contains("]"))
|
||||||
{
|
{
|
||||||
value = value.Substring(value.IndexOf("]") + 1);
|
value = value.Substring(value.IndexOf("]") + 1);
|
||||||
@ -214,25 +255,29 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (username != string.Empty && email != string.Empty)
|
if (_username != string.Empty && _email != string.Empty)
|
||||||
{
|
{
|
||||||
if (_password == confirm)
|
if (_password == _confirm)
|
||||||
{
|
{
|
||||||
if (ValidateProfiles())
|
if (ValidateProfiles())
|
||||||
{
|
{
|
||||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
var user = await UserService.GetUserAsync(_userid, PageState.Site.SiteId);
|
||||||
user.SiteId = PageState.Site.SiteId;
|
user.SiteId = PageState.Site.SiteId;
|
||||||
user.Username = username;
|
user.Username = _username;
|
||||||
user.Password = _password;
|
user.Password = _password;
|
||||||
user.Email = email;
|
user.Email = _email;
|
||||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
user.EmailConfirmed = bool.Parse(_confirmed);
|
||||||
|
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
||||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
user.TimeZoneId = _timezoneid;
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
user.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||||
|
}
|
||||||
|
|
||||||
user = await UserService.UpdateUserAsync(user);
|
user = await UserService.UpdateUserAsync(user);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
await SettingService.UpdateUserSettingsAsync(_settings, user.UserId);
|
||||||
await logger.LogInformation("User Saved {User}", user);
|
await logger.LogInformation("User Saved {User}", user);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
@ -254,19 +299,57 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Saving User {Username} {Email} {Error}", username, email, ex.Message);
|
await logger.LogError(ex, "Error Saving User {Username} {Email} {Error}", _username, _email, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.User.Save"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.User.Save"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ImpersonateUser()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await logger.LogInformation(LogFunction.Security, "User {Username} Impersonated By Administrator {Administrator}", _username, PageState.User.Username);
|
||||||
|
|
||||||
|
// post back to the server so that the cookies are set correctly
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
|
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, returnurl = PageState.Alias.Path };
|
||||||
|
string url = Utilities.TenantUrl(PageState.Alias, "/pages/impersonate/");
|
||||||
|
await interop.SubmitForm(url, fields);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Impersonating User {Username} {Error}", _username, ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.User.Impersonate"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteUser()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && _userid != PageState.User.UserId)
|
||||||
|
{
|
||||||
|
var user = await UserService.GetUserAsync(_userid, PageState.Site.SiteId);
|
||||||
|
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
|
||||||
|
await logger.LogInformation("User Permanently Deleted {User}", user);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Permanently Deleting User {UserId} {Error}", _userid, ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.DeleteUser"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool ValidateProfiles()
|
private bool ValidateProfiles()
|
||||||
{
|
{
|
||||||
foreach (Profile profile in profiles)
|
foreach (Profile profile in _profiles)
|
||||||
{
|
{
|
||||||
var value = GetProfileValue(profile.Name, string.Empty);
|
var value = GetProfileValue(profile.Name, string.Empty);
|
||||||
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
|
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
|
||||||
{
|
{
|
||||||
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
|
_settings = SettingService.SetSetting(_settings, profile.Name, profile.DefaultValue);
|
||||||
}
|
}
|
||||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
@ -293,7 +376,7 @@
|
|||||||
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
||||||
{
|
{
|
||||||
var value = (string)e.Value;
|
var value = (string)e.Value;
|
||||||
settings = SettingService.SetSetting(settings, SettingName, value);
|
_settings = SettingService.SetSetting(_settings, SettingName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TogglePassword()
|
private void TogglePassword()
|
||||||
|
@ -17,171 +17,174 @@ else
|
|||||||
{
|
{
|
||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Users" Heading="Users" ResourceKey="Users">
|
<TabPanel Name="Users" Heading="Users" ResourceKey="Users">
|
||||||
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
||||||
<ActionLink Text="Import Users" Class="btn btn-secondary ms-2" Action="Users" Security="SecurityAccessLevel.Admin" ResourceKey="ImportUsers"/>
|
<ActionLink Text="Import Users" Class="btn btn-secondary ms-2" Action="Users" Security="SecurityAccessLevel.Admin" ResourceKey="ImportUsers"/>
|
||||||
|
|
||||||
<Pager Items="@users" RowClass="align-middle" SearchProperties="User.Username,User.Email,User.DisplayName">
|
<Pager Items="@users" RowClass="align-middle" SearchProperties="User.Username,User.Email,User.DisplayName">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("Username"))">@Localizer["Username"]<i class="@(SetSortIcon("Username"))"></i></th>
|
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("Username"))">@Localizer["Username"]<i class="@(SetSortIcon("Username"))"></i></th>
|
||||||
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("DisplayName"))">@Localizer["Name"]<i class="@(SetSortIcon("DisplayName"))"></i></th>
|
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("DisplayName"))">@Localizer["Name"]<i class="@(SetSortIcon("DisplayName"))"></i></th>
|
||||||
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("Email"))">@Localizer["Email"]<i class="@(SetSortIcon("Email"))"></i></th>
|
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("Email"))">@Localizer["Email"]<i class="@(SetSortIcon("Email"))"></i></th>
|
||||||
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("LastLoginOn"))">@Localizer["LastLoginOn"]<i class="@(SetSortIcon("LastLoginOn"))"></i></th>
|
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("LastLoginOn"))">@Localizer["LastLoginOn"]<i class="@(SetSortIcon("LastLoginOn"))"></i></th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td>
|
<td>
|
||||||
<ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditUser" />
|
<ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditUser" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
|
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId || context.User.IsDeleted)" ResourceKey="DeleteUser" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionLink Action="Roles" Text="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
<ActionLink Action="Roles" Text="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
||||||
</td>
|
</td>
|
||||||
<td>@context.User.Username</td>
|
<td>@context.User.Username</td>
|
||||||
<td>@context.User.DisplayName</td>
|
<td>@context.User.DisplayName</td>
|
||||||
<td>@((MarkupString)string.Format("<a href=\"mailto:{0}\">{1}</a>", @context.User.Email, @context.User.Email))</td>
|
<td>@((MarkupString)string.Format("<a href=\"mailto:{0}\">{1}</a>", @context.User.Email, @context.User.Email))</td>
|
||||||
<td>@((context.User.LastLoginOn != DateTime.MinValue) ? string.Format("{0:dd-MMM-yyyy HH:mm:ss}", context.User.LastLoginOn) : "")</td>
|
<td>@((context.User.LastLoginOn != DateTime.MinValue) ? string.Format("{0:dd-MMM-yyyy HH:mm:ss}", UtcToLocal(context.User.LastLoginOn)) : "")</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings" Security="SecurityAccessLevel.Admin">
|
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings" Security="SecurityAccessLevel.Admin">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<Section Name="User" Heading="User Settings" ResourceKey="UserSettings">
|
<Section Name="User" Heading="User Settings" ResourceKey="UserSettings">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="allowregistration" HelpText="Do you want anonymous visitors to be able to register for an account on the site" ResourceKey="AllowRegistration">Allow User Registration?</Label>
|
<Label Class="col-sm-3" For="allowregistration" HelpText="Do you want anonymous visitors to be able to register for an account on the site" ResourceKey="AllowRegistration">Allow User Registration?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="allowregistration" class="form-select" @bind="@_allowregistration">
|
<select id="allowregistration" class="form-select" @bind="@_allowregistration">
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (_providertype != "")
|
@if (_allowregistration == "true")
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="allowsitelogin" HelpText="Do you want to allow users to sign in using a username and password that is managed locally on this site? Note that you should only disable this option if you have already sucessfully configured an external login provider, or else you may lock yourself out of the site." ResourceKey="AllowSiteLogin">Allow Login?</Label>
|
<Label Class="col-sm-3" For="registerurl" HelpText="Optionally provide a custom registration url" ResourceKey="RegisterUrl">Register Url:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="allowsitelogin" class="form-select" @bind="@_allowsitelogin">
|
<input id="registerurl" class="form-control" @bind="@_registerurl" />
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
</div>
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
</div>
|
||||||
</select>
|
}
|
||||||
</div>
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="profileurl" HelpText="Optionally provide a custom profile url" ResourceKey="ProfileUrl">Profile Url:</Label>
|
||||||
}
|
<div class="col-sm-9">
|
||||||
else
|
<input id="profileurl" class="form-control" @bind="@_profileurl" />
|
||||||
{
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
</div>
|
||||||
<Label Class="col-sm-3" For="allowsitelogin" HelpText="Do you want to allow users to sign in using a username and password that is managed locally on this site? Note that you should only disable this option if you have already sucessfully configured an external login provider, or else you may lock yourself out of the site." ResourceKey="AllowSiteLogin">Allow Login?</Label>
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
<div class="col-sm-9">
|
{
|
||||||
<input id="allowsitelogin" class="form-control" value="@SharedLocalizer["Yes"]" readonly />
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="twofactor" HelpText="Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out." ResourceKey="TwoFactor">Two Factor?</Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
}
|
<select id="twofactor" class="form-select" @bind="@_twofactor">
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
<option value="false">@Localizer["Disabled"]</option>
|
||||||
{
|
<option value="true">@Localizer["Optional"]</option>
|
||||||
<div class="row mb-1 align-items-center">
|
<option value="required">@Localizer["Required"]</option>
|
||||||
<Label Class="col-sm-3" For="twofactor" HelpText="Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out." ResourceKey="TwoFactor">Two Factor?</Label>
|
</select>
|
||||||
<div class="col-sm-9">
|
</div>
|
||||||
<select id="twofactor" class="form-select" @bind="@_twofactor">
|
</div>
|
||||||
<option value="false">@Localizer["Disabled"]</option>
|
<div class="row mb-1 align-items-center">
|
||||||
<option value="true">@Localizer["Optional"]</option>
|
<Label Class="col-sm-3" For="cookiename" HelpText="You can choose to use a custom authentication cookie name for each site. However please be aware that if you want to share an authentication cookie between sites on the same domain they need to use a consistent cookie name. Also be aware that changing the authentication cookie name will logout all current users." ResourceKey="CookieName">Cookie Name:</Label>
|
||||||
<option value="required">@Localizer["Required"]</option>
|
<div class="col-sm-9">
|
||||||
</select>
|
<input id="cookiename" class="form-control" @bind="@_cookiename" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="cookiename" HelpText="You can choose to use a custom authentication cookie name for each site. However please be aware that if you want to share an authentication cookie between sites on the same domain they need to use a consistent cookie name. Also be aware that changing the authentication cookie name will logout all current users." ResourceKey="CookieName">Cookie Name:</Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="cookiename" class="form-control" @bind="@_cookiename" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="cookieexpiration" HelpText="You can choose to use a custom authentication cookie expiration timespan for each site (e.g. '08:00:00' for 8 hours). The default is 14 days if not specified." ResourceKey="CookieExpiration">Cookie Expiration Timespan:</Label>
|
<Label Class="col-sm-3" For="cookieexpiration" HelpText="You can choose to use a custom authentication cookie expiration timespan for each site (e.g. '08:00:00' for 8 hours). The default is 14 days if not specified." ResourceKey="CookieExpiration">Cookie Expiration Timespan:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="cookieexpiration" class="form-control" @bind="@_cookieexpiration" />
|
<input id="cookieexpiration" class="form-control" @bind="@_cookieexpiration" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="alwaysremember" HelpText="Enabling this option will set a permanent cookie in conjunction with the Cookie Expiration Timespan, which will automatically sign in users the next time they visit the site. By default the site will use session cookies." ResourceKey="AlwaysRemember">Always Remember User?</Label>
|
<Label Class="col-sm-3" For="alwaysremember" HelpText="Enabling this option will set a permanent cookie in conjunction with the Cookie Expiration Timespan, which will automatically sign in users the next time they visit the site. By default the site will use session cookies." ResourceKey="AlwaysRemember">Always Remember User?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="alwaysremember" class="form-select" @bind="@_alwaysremember">
|
<select id="alwaysremember" class="form-select" @bind="@_alwaysremember">
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
<div class="row mb-1 align-items-center">
|
||||||
</Section>
|
<Label Class="col-sm-3" For="logouteverywhere" HelpText="Do you want users to be logged out of every active session on any device, or only their current session?" ResourceKey="LogoutEverywhere">Logout Everywhere?</Label>
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
<div class="col-sm-9">
|
||||||
{
|
<select id="logouteverywhere" class="form-select" @bind="@_logouteverywhere">
|
||||||
<Section Name="Password" Heading="Password Settings" ResourceKey="PasswordSettings">
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
<div class="row mb-1 align-items-center">
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
<Label Class="col-sm-3" For="minimumlength" HelpText="The Minimum Length For A Password" ResourceKey="RequiredLength">Minimum Length:</Label>
|
</select>
|
||||||
<div class="col-sm-9">
|
</div>
|
||||||
<input id="minimumlength" class="form-control" @bind="@_minimumlength" required />
|
</div>
|
||||||
</div>
|
}
|
||||||
</div>
|
</Section>
|
||||||
<div class="row mb-1 align-items-center">
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
<Label Class="col-sm-3" For="uniquecharacters" HelpText="The Minimum Number Of Unique Characters Which A Password Must Contain" ResourceKey="UniqueCharacters">Unique Characters:</Label>
|
{
|
||||||
<div class="col-sm-9">
|
<Section Name="Password" Heading="Password Settings" ResourceKey="PasswordSettings">
|
||||||
<input id="uniquecharacters" class="form-control" @bind="@_uniquecharacters" required />
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="minimumlength" HelpText="The Minimum Length For A Password" ResourceKey="RequiredLength">Minimum Length:</Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
<div class="row mb-1 align-items-center">
|
<input id="minimumlength" class="form-control" @bind="@_minimumlength" required />
|
||||||
<Label Class="col-sm-3" For="requiredigit" HelpText="Indicate If Passwords Must Contain A Digit" ResourceKey="RequireDigit">Require Digit?</Label>
|
</div>
|
||||||
<div class="col-sm-9">
|
</div>
|
||||||
<select id="requiredigit" class="form-select" @bind="@_requiredigit" required>
|
<div class="row mb-1 align-items-center">
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
<Label Class="col-sm-3" For="uniquecharacters" HelpText="The Minimum Number Of Unique Characters Which A Password Must Contain" ResourceKey="UniqueCharacters">Unique Characters:</Label>
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
<div class="col-sm-9">
|
||||||
</select>
|
<input id="uniquecharacters" class="form-control" @bind="@_uniquecharacters" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="requireupper" HelpText="Indicate If Passwords Must Contain An Upper Case Character" ResourceKey="RequireUpper">Require Uppercase?</Label>
|
<Label Class="col-sm-3" For="requiredigit" HelpText="Indicate If Passwords Must Contain A Digit" ResourceKey="RequireDigit">Require Digit?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="requireupper" class="form-select" @bind="@_requireupper" required>
|
<select id="requiredigit" class="form-select" @bind="@_requiredigit" required>
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="requirelower" HelpText="Indicate If Passwords Must Contain A Lower Case Character" ResourceKey="RequireLower">Require Lowercase?</Label>
|
<Label Class="col-sm-3" For="requireupper" HelpText="Indicate If Passwords Must Contain An Upper Case Character" ResourceKey="RequireUpper">Require Uppercase?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="requirelower" class="form-select" @bind="@_requirelower" required>
|
<select id="requireupper" class="form-select" @bind="@_requireupper" required>
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="requirepunctuation" HelpText="Indicate if Passwords Must Contain A Non-alphanumeric Character (ie. Punctuation)" ResourceKey="RequirePunctuation">Require Punctuation?</Label>
|
<Label Class="col-sm-3" For="requirelower" HelpText="Indicate If Passwords Must Contain A Lower Case Character" ResourceKey="RequireLower">Require Lowercase?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="requirepunctuation" class="form-select" @bind="@_requirepunctuation" required>
|
<select id="requirelower" class="form-select" @bind="@_requirelower" required>
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
<div class="row mb-1 align-items-center">
|
||||||
<Section Name="Lockout" Heading="Lockout Settings" ResourceKey="LockoutSettings">
|
<Label Class="col-sm-3" For="requirepunctuation" HelpText="Indicate if Passwords Must Contain A Non-alphanumeric Character (ie. Punctuation)" ResourceKey="RequirePunctuation">Require Punctuation?</Label>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="col-sm-9">
|
||||||
<Label Class="col-sm-3" For="maximum" HelpText="The Maximum Number Of Sign In Attempts Before A User Is Locked Out" ResourceKey="MaximumFailures">Maximum Failures:</Label>
|
<select id="requirepunctuation" class="form-select" @bind="@_requirepunctuation" required>
|
||||||
<div class="col-sm-9">
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
<input id="maximum" class="form-control" @bind="@_maximumfailures" required />
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
</div>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
</div>
|
||||||
<Label Class="col-sm-3" For="lockoutduration" HelpText="The Number Of Minutes A User Should Be Locked Out" ResourceKey="LockoutDuration">Lockout Duration:</Label>
|
</Section>
|
||||||
<div class="col-sm-9">
|
<Section Name="Lockout" Heading="Lockout Settings" ResourceKey="LockoutSettings">
|
||||||
<input id="lockoutduration" class="form-control" @bind="@_lockoutduration" required />
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="maximum" HelpText="The Maximum Number Of Sign In Attempts Before A User Is Locked Out" ResourceKey="MaximumFailures">Maximum Failures:</Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
</Section>
|
<input id="maximum" class="form-control" @bind="@_maximumfailures" required />
|
||||||
<Section Name="ExternalLogin" Heading="External Login Settings" ResourceKey="ExternalLoginSettings">
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="lockoutduration" HelpText="The Number Of Minutes A User Should Be Locked Out" ResourceKey="LockoutDuration">Lockout Duration:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="lockoutduration" class="form-control" @bind="@_lockoutduration" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
<Section Name="ExternalLogin" Heading="External Login Settings" ResourceKey="ExternalLoginSettings">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="provider" HelpText="Select the external login provider" ResourceKey="Provider">Provider:</Label>
|
<Label Class="col-sm-3" For="provider" HelpText="Select the external login provider" ResourceKey="Provider">Provider:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -201,77 +204,77 @@ else
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="providertype" HelpText="Select the external login provider type" ResourceKey="ProviderType">Provider Type:</Label>
|
<Label Class="col-sm-3" For="providertype" HelpText="Select the external login provider type" ResourceKey="ProviderType">Provider Type:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="providertype" class="form-select" value="@_providertype" @onchange="(e => ProviderTypeChanged(e))">
|
<select id="providertype" class="form-select" value="@_providertype" @onchange="(e => ProviderTypeChanged(e))">
|
||||||
<option value="" selected><@Localizer["Not Specified"]></option>
|
<option value="" selected><@Localizer["Not Specified"]></option>
|
||||||
<option value="@AuthenticationProviderTypes.OpenIDConnect">@Localizer["OIDC"]</option>
|
<option value="@AuthenticationProviderTypes.OpenIDConnect">@Localizer["OIDC"]</option>
|
||||||
<option value="@AuthenticationProviderTypes.OAuth2">@Localizer["OAuth2"]</option>
|
<option value="@AuthenticationProviderTypes.OAuth2">@Localizer["OAuth2"]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (_providertype != "")
|
@if (_providertype != "")
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="providername" HelpText="Specify a friendly name for the external login provider which will be displayed on the Login page" ResourceKey="ProviderName">Provider Name:</Label>
|
<Label Class="col-sm-3" For="providername" HelpText="Specify a friendly name for the external login provider which will be displayed on the Login page" ResourceKey="ProviderName">Provider Name:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="providername" class="form-control" @bind="@_providername" />
|
<input id="providername" class="form-control" @bind="@_providername" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (_providertype == AuthenticationProviderTypes.OpenIDConnect)
|
@if (_providertype == AuthenticationProviderTypes.OpenIDConnect)
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="authority" HelpText="The Authority Url or Issuer Url associated with the OpenID Connect provider" ResourceKey="Authority">Authority:</Label>
|
<Label Class="col-sm-3" For="authority" HelpText="The Authority Url or Issuer Url associated with the OpenID Connect provider" ResourceKey="Authority">Authority:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="authority" class="form-control" @bind="@_authority" />
|
<input id="authority" class="form-control" @bind="@_authority" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="metadataurl" HelpText="The discovery endpoint for obtaining metadata for this provider. Only specify if the OpenID Connect provider does not use the standard approach (ie. /.well-known/openid-configuration)" ResourceKey="MetadataUrl">Metadata Url:</Label>
|
<Label Class="col-sm-3" For="metadataurl" HelpText="The discovery endpoint for obtaining metadata for this provider. Only specify if the OpenID Connect provider does not use the standard approach (ie. /.well-known/openid-configuration)" ResourceKey="MetadataUrl">Metadata Url:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="metadataurl" class="form-control" @bind="@_metadataurl" />
|
<input id="metadataurl" class="form-control" @bind="@_metadataurl" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (_providertype == AuthenticationProviderTypes.OAuth2)
|
@if (_providertype == AuthenticationProviderTypes.OAuth2)
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="authorizationurl" HelpText="The endpoint for obtaining an Authorization Code" ResourceKey="AuthorizationUrl">Authorization Url:</Label>
|
<Label Class="col-sm-3" For="authorizationurl" HelpText="The endpoint for obtaining an Authorization Code" ResourceKey="AuthorizationUrl">Authorization Url:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="authorizationurl" class="form-control" @bind="@_authorizationurl" />
|
<input id="authorizationurl" class="form-control" @bind="@_authorizationurl" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="tokenurl" HelpText="The endpoint for obtaining an Auth Token" ResourceKey="TokenUrl">Token Url:</Label>
|
<Label Class="col-sm-3" For="tokenurl" HelpText="The endpoint for obtaining an Auth Token" ResourceKey="TokenUrl">Token Url:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="tokenurl" class="form-control" @bind="@_tokenurl" />
|
<input id="tokenurl" class="form-control" @bind="@_tokenurl" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="userinfourl" HelpText="The endpoint for obtaining user information. This should be an API or Page Url which contains the users email address." ResourceKey="UserInfoUrl">User Info Url:</Label>
|
<Label Class="col-sm-3" For="userinfourl" HelpText="The endpoint for obtaining user information. This should be an API or Page Url which contains the users email address." ResourceKey="UserInfoUrl">User Info Url:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="userinfourl" class="form-control" @bind="@_userinfourl" />
|
<input id="userinfourl" class="form-control" @bind="@_userinfourl" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (_providertype != "")
|
@if (_providertype != "")
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="clientid" HelpText="The Client ID from the provider" ResourceKey="ClientID">Client ID:</Label>
|
<Label Class="col-sm-3" For="clientid" HelpText="The Client ID from the provider" ResourceKey="ClientID">Client ID:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="clientid" class="form-control" @bind="@_clientid" />
|
<input id="clientid" class="form-control" @bind="@_clientid" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="clientsecret" HelpText="The Client Secret from the provider" ResourceKey="ClientSecret">Client Secret:</Label>
|
<Label Class="col-sm-3" For="clientsecret" HelpText="The Client Secret from the provider" ResourceKey="ClientSecret">Client Secret:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="@_clientsecrettype" id="clientsecret" class="form-control" @bind="@_clientsecret" />
|
<input type="@_clientsecrettype" id="clientsecret" class="form-control" @bind="@_clientsecret" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleClientSecret">@_toggleclientsecret</button>
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleClientSecret">@_toggleclientsecret</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (_providertype == AuthenticationProviderTypes.OpenIDConnect)
|
@if (_providertype == AuthenticationProviderTypes.OpenIDConnect)
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -291,32 +294,32 @@ else
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="scopes" HelpText="A list of Scopes to request from the provider (separated by commas). If none are specified, standard Scopes will be used by default." ResourceKey="Scopes">Scopes:</Label>
|
<Label Class="col-sm-3" For="scopes" HelpText="A list of Scopes to request from the provider (separated by commas). If none are specified, standard Scopes will be used by default." ResourceKey="Scopes">Scopes:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="scopes" class="form-control" @bind="@_scopes" />
|
<input id="scopes" class="form-control" @bind="@_scopes" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="parameters" HelpText="Optionally specify any additional parameters as name/value pairs to send to the provider (separated by commas if there are multiple)." ResourceKey="Parameters">Parameters:</Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="parameters" class="form-control" @bind="@_parameters" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="pkce" HelpText="Indicate if the provider supports Proof Key for Code Exchange (PKCE)" ResourceKey="PKCE">Use PKCE?</Label>
|
<Label Class="col-sm-3" For="parameters" HelpText="Optionally specify any additional parameters as name/value pairs to send to the provider (separated by commas if there are multiple)." ResourceKey="Parameters">Parameters:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="pkce" class="form-select" @bind="@_pkce" required>
|
<input id="parameters" class="form-control" @bind="@_parameters" />
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
</div>
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
</div>
|
||||||
</select>
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="pkce" HelpText="Indicate if the provider supports Proof Key for Code Exchange (PKCE)" ResourceKey="PKCE">Use PKCE?</Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
<div class="row mb-1 align-items-center">
|
<select id="pkce" class="form-select" @bind="@_pkce" required>
|
||||||
<Label Class="col-sm-3" For="redirecturl" HelpText="The Redirect Url (or Callback Url) which usually needs to be registered with the provider" ResourceKey="RedirectUrl">Redirect Url:</Label>
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
<div class="col-sm-9">
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
<input id="redirecturl" class="form-control" @bind="@_redirecturl" readonly />
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="redirecturl" HelpText="The Redirect Url (or Callback Url) which usually needs to be registered with the provider" ResourceKey="RedirectUrl">Redirect Url:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="redirecturl" class="form-control" @bind="@_redirecturl" readonly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="reviewclaims" HelpText="This option will record the full list of Claims returned by the Provider in the Event Log. It should only be used for testing purposes. External Login will be restricted when this option is enabled." ResourceKey="ReviewClaims">Review Claims?</Label>
|
<Label Class="col-sm-3" For="reviewclaims" HelpText="This option will record the full list of Claims returned by the Provider in the Event Log. It should only be used for testing purposes. External Login will be restricted when this option is enabled." ResourceKey="ReviewClaims">Review Claims?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -334,10 +337,10 @@ else
|
|||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="identifierclaimtype" HelpText="Specify the type name of the unique user identifier claim provided by the provider. The default value is 'sub'." ResourceKey="IdentifierClaimType">Identifier Claim:</Label>
|
<Label Class="col-sm-3" For="identifierclaimtype" HelpText="Specify the type name of the unique user identifier claim provided by the provider. The default value is 'sub'." ResourceKey="IdentifierClaimType">Identifier Claim:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="identifierclaimtype" class="form-control" @bind="@_identifierclaimtype" />
|
<input id="identifierclaimtype" class="form-control" @bind="@_identifierclaimtype" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="nameclaimtype" HelpText="Optionally specify the type name of the user's name claim provided by the provider. The typical value is 'name'." ResourceKey="NameClaimType">Name Claim:</Label>
|
<Label Class="col-sm-3" For="nameclaimtype" HelpText="Optionally specify the type name of the user's name claim provided by the provider. The typical value is 'name'." ResourceKey="NameClaimType">Name Claim:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -346,16 +349,16 @@ else
|
|||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="emailclaimtype" HelpText="Optionally specify the type name of the email address claim provided by the provider. The typical value is 'email'," ResourceKey="EmailClaimType">Email Claim:</Label>
|
<Label Class="col-sm-3" For="emailclaimtype" HelpText="Optionally specify the type name of the email address claim provided by the provider. The typical value is 'email'," ResourceKey="EmailClaimType">Email Claim:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="emailclaimtype" class="form-control" @bind="@_emailclaimtype" />
|
<input id="emailclaimtype" class="form-control" @bind="@_emailclaimtype" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="roleclaimtype" HelpText="The name of the roles claim provided by the provider" ResourceKey="RoleClaimType">Roles Claim:</Label>
|
<Label Class="col-sm-3" For="roleclaimtype" HelpText="The name of the roles claim provided by the provider" ResourceKey="RoleClaimType">Roles Claim:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="roleclaimtype" class="form-control" @bind="@_roleclaimtype" />
|
<input id="roleclaimtype" class="form-control" @bind="@_roleclaimtype" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="roleclaimmappings" HelpText="Optionally provide a comma delimited list of role names provided by the identity provider, as well as mappings to your site roles." ResourceKey="RoleClaimMappings">Role Claim Mappings:</Label>
|
<Label Class="col-sm-3" For="roleclaimmappings" HelpText="Optionally provide a comma delimited list of role names provided by the identity provider, as well as mappings to your site roles." ResourceKey="RoleClaimMappings">Role Claim Mappings:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -374,26 +377,35 @@ else
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="profileclaimtypes" HelpText="A comma delimited list of user profile claims provided by the provider, as well as mappings to your user profile definition. For example if the provider includes a 'given_name' claim and you have a 'FirstName' user profile definition you should specify 'given_name:FirstName'." ResourceKey="ProfileClaimTypes">User Profile Claims:</Label>
|
<Label Class="col-sm-3" For="profileclaimtypes" HelpText="A comma delimited list of user profile claims provided by the provider, as well as mappings to your user profile definition. For example if the provider includes a 'given_name' claim and you have a 'FirstName' user profile definition you should specify 'given_name:FirstName'." ResourceKey="ProfileClaimTypes">User Profile Claims:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="profileclaimtypes" class="form-control" @bind="@_profileclaimtypes" />
|
<input id="profileclaimtypes" class="form-control" @bind="@_profileclaimtypes" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="domainfilter" HelpText="Provide any email domain filter criteria (separated by commas). Domains to exclude should be prefixed with an exclamation point (!). For example 'microsoft.com,!hotmail.com' would include microsoft.com email addresses but not hotmail.com email addresses." ResourceKey="DomainFilter">Domain Filter:</Label>
|
<Label Class="col-sm-3" For="savetokens" HelpText="Specify whether access and refresh tokens should be saved after a successful login. The default is false to reduce the size of the authentication cookie." ResourceKey="SaveTokens">Save Tokens?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="domainfilter" class="form-control" @bind="@_domainfilter" />
|
<select id="savetokens" class="form-select" @bind="@_savetokens" required>
|
||||||
</div>
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
</div>
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
<div class="row mb-1 align-items-center">
|
</select>
|
||||||
<Label Class="col-sm-3" For="createusers" HelpText="Do you want new users to be created automatically? If you disable this option, users must already be registered on the site in order to sign in with their external login." ResourceKey="CreateUsers">Create New Users?</Label>
|
</div>
|
||||||
<div class="col-sm-9">
|
</div>
|
||||||
<select id="createusers" class="form-select" @bind="@_createusers">
|
<div class="row mb-1 align-items-center">
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
<Label Class="col-sm-3" For="domainfilter" HelpText="Provide any email domain filter criteria (separated by commas). Domains to exclude should be prefixed with an exclamation point (!). For example 'microsoft.com,!hotmail.com' would include microsoft.com email addresses but not hotmail.com email addresses." ResourceKey="DomainFilter">Domain Filter:</Label>
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
<div class="col-sm-9">
|
||||||
</select>
|
<input id="domainfilter" class="form-control" @bind="@_domainfilter" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="createusers" HelpText="Do you want new users to be created automatically? If you disable this option, users must already be registered on the site in order to sign in with their external login." ResourceKey="CreateUsers">Create New Users?</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="createusers" class="form-select" @bind="@_createusers">
|
||||||
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="verifyusers" HelpText="Do you want existing users to perform an additional email verification step to link their external login? If you disable this option, existing users will be linked automatically." ResourceKey="VerifyUsers">Verify Existing Users?</Label>
|
<Label Class="col-sm-3" For="verifyusers" HelpText="Do you want existing users to perform an additional email verification step to link their external login? If you disable this option, existing users will be linked automatically." ResourceKey="VerifyUsers">Verify Existing Users?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -403,63 +415,86 @@ else
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="allowhostrole" HelpText="Indicate if host roles are supported from the identity provider. Please use caution with this option as it allows the host user to administrate every site within your installation." ResourceKey="AllowHostRole">Allow Host Role?</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="allowhostrole" class="form-select" @bind="@_allowhostrole" required>
|
||||||
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="allowsitelogin" HelpText="Do you want to allow users to sign in using a username and password that is managed locally on this site? Note that you should only disable this option if you have already sucessfully configured an external login provider, or else you may lock yourself out of the site." ResourceKey="AllowSiteLogin">Allow Local Login?</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="allowsitelogin" class="form-select" @bind="@_allowsitelogin">
|
||||||
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="Token" Heading="Token Settings" ResourceKey="TokenSettings">
|
<Section Name="Token" Heading="Token Settings" ResourceKey="TokenSettings">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="jwtsecret" HelpText="If you want to want to provide API access, please specify a secret which will be used to encrypt your tokens. The secret should be 16 characters or more to ensure optimal security. Please note that if you change this secret, all existing tokens will become invalid and will need to be regenerated." ResourceKey="Secret">Secret:</Label>
|
<Label Class="col-sm-3" For="jwtsecret" HelpText="If you want to want to provide API access, please specify a secret which will be used to encrypt your tokens. The secret should be 16 characters or more to ensure optimal security. Please note that if you change this secret, all existing tokens will become invalid and will need to be regenerated." ResourceKey="Secret">Secret:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="@_secrettype" id="jwtsecret" class="form-control" @bind="@_secret" />
|
<input type="@_secrettype" id="jwtsecret" class="form-control" @bind="@_secret" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleSecret">@_togglesecret</button>
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleSecret">@_togglesecret</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="issuer" HelpText="Optionally provide the issuer of the token" ResourceKey="Issuer">Issuer:</Label>
|
<Label Class="col-sm-3" For="issuer" HelpText="Optionally provide the issuer of the token" ResourceKey="Issuer">Issuer:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="issuer" class="form-control" @bind="@_issuer" />
|
<input id="issuer" class="form-control" @bind="@_issuer" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="audience" HelpText="Optionally provide the audience for the token" ResourceKey="Audience">Audience:</Label>
|
<Label Class="col-sm-3" For="audience" HelpText="Optionally provide the audience for the token" ResourceKey="Audience">Audience:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="audience" class="form-control" @bind="@_audience" />
|
<input id="audience" class="form-control" @bind="@_audience" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="lifetime" HelpText="The number of minutes for which a token should be valid" ResourceKey="Lifetime">Lifetime:</Label>
|
<Label Class="col-sm-3" For="lifetime" HelpText="The number of minutes for which a token should be valid" ResourceKey="Lifetime">Lifetime:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="lifetime" class="form-control" @bind="@_lifetime" />
|
<input id="lifetime" class="form-control" @bind="@_lifetime" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="token" HelpText="Select the Create Token button to generate a long-lived access token (valid for 1 year). Be sure to store this token in a safe location as you will not be able to access it in the future." ResourceKey="Token">Access Token:</Label>
|
<Label Class="col-sm-3" For="token" HelpText="Select the Create Token button to generate a long-lived access token (valid for 1 year). Be sure to store this token in a safe location as you will not be able to access it in the future." ResourceKey="Token">Access Token:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="token" class="form-control" @bind="@_token" />
|
<input id="token" class="form-control" @bind="@_token" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@CreateToken">@Localizer["CreateToken"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="@CreateToken">@Localizer["CreateToken"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<UserRole> users;
|
private List<UserRole> users;
|
||||||
|
|
||||||
private string _allowregistration;
|
private string _allowregistration;
|
||||||
private string _allowsitelogin;
|
private string _registerurl;
|
||||||
|
private string _profileurl;
|
||||||
private string _twofactor;
|
private string _twofactor;
|
||||||
private string _cookiename;
|
private string _cookiename;
|
||||||
private string _cookieexpiration;
|
private string _cookieexpiration;
|
||||||
private string _alwaysremember;
|
private string _alwaysremember;
|
||||||
|
private string _logouteverywhere;
|
||||||
|
|
||||||
private string _minimumlength;
|
private string _minimumlength;
|
||||||
private string _uniquecharacters;
|
private string _uniquecharacters;
|
||||||
@ -497,9 +532,12 @@ else
|
|||||||
private string _roleclaimmappings;
|
private string _roleclaimmappings;
|
||||||
private string _synchronizeroles;
|
private string _synchronizeroles;
|
||||||
private string _profileclaimtypes;
|
private string _profileclaimtypes;
|
||||||
|
private string _savetokens;
|
||||||
private string _domainfilter;
|
private string _domainfilter;
|
||||||
private string _createusers;
|
private string _createusers;
|
||||||
private string _verifyusers;
|
private string _verifyusers;
|
||||||
|
private string _allowhostrole;
|
||||||
|
private string _allowsitelogin;
|
||||||
|
|
||||||
private string _secret;
|
private string _secret;
|
||||||
private string _secrettype = "password";
|
private string _secrettype = "password";
|
||||||
@ -519,8 +557,9 @@ else
|
|||||||
await LoadUsersAsync(true);
|
await LoadUsersAsync(true);
|
||||||
|
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
_allowregistration = PageState.Site.AllowRegistration.ToString();
|
_allowregistration = PageState.Site.AllowRegistration.ToString().ToLower();
|
||||||
_allowsitelogin = SettingService.GetSetting(settings, "LoginOptions:AllowSiteLogin", "true");
|
_registerurl = SettingService.GetSetting(settings, "LoginOptions:RegisterUrl", "");
|
||||||
|
_profileurl = SettingService.GetSetting(settings, "LoginOptions:ProfileUrl", "");
|
||||||
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
@ -528,6 +567,7 @@ else
|
|||||||
_cookiename = SettingService.GetSetting(settings, "LoginOptions:CookieName", ".AspNetCore.Identity.Application");
|
_cookiename = SettingService.GetSetting(settings, "LoginOptions:CookieName", ".AspNetCore.Identity.Application");
|
||||||
_cookieexpiration = SettingService.GetSetting(settings, "LoginOptions:CookieExpiration", "");
|
_cookieexpiration = SettingService.GetSetting(settings, "LoginOptions:CookieExpiration", "");
|
||||||
_alwaysremember = SettingService.GetSetting(settings, "LoginOptions:AlwaysRemember", "false");
|
_alwaysremember = SettingService.GetSetting(settings, "LoginOptions:AlwaysRemember", "false");
|
||||||
|
_logouteverywhere = SettingService.GetSetting(settings, "LoginOptions:LogoutEverywhere", "false");
|
||||||
|
|
||||||
_minimumlength = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredLength", "6");
|
_minimumlength = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredLength", "6");
|
||||||
_uniquecharacters = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", "1");
|
_uniquecharacters = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", "1");
|
||||||
@ -577,9 +617,12 @@ else
|
|||||||
_roleclaimmappings = SettingService.GetSetting(settings, "ExternalLogin:RoleClaimMappings", "");
|
_roleclaimmappings = SettingService.GetSetting(settings, "ExternalLogin:RoleClaimMappings", "");
|
||||||
_synchronizeroles = SettingService.GetSetting(settings, "ExternalLogin:SynchronizeRoles", "false");
|
_synchronizeroles = SettingService.GetSetting(settings, "ExternalLogin:SynchronizeRoles", "false");
|
||||||
_profileclaimtypes = SettingService.GetSetting(settings, "ExternalLogin:ProfileClaimTypes", "");
|
_profileclaimtypes = SettingService.GetSetting(settings, "ExternalLogin:ProfileClaimTypes", "");
|
||||||
|
_savetokens = SettingService.GetSetting(settings, "ExternalLogin:SaveTokens", "false");
|
||||||
_domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", "");
|
_domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", "");
|
||||||
_createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true");
|
_createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true");
|
||||||
_verifyusers = SettingService.GetSetting(settings, "ExternalLogin:VerifyUsers", "true");
|
_verifyusers = SettingService.GetSetting(settings, "ExternalLogin:VerifyUsers", "true");
|
||||||
|
_allowhostrole = SettingService.GetSetting(settings, "ExternalLogin:AllowHostRole", "false");
|
||||||
|
_allowsitelogin = SettingService.GetSetting(settings, "LoginOptions:AllowSiteLogin", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadUsersAsync(bool load)
|
private async Task LoadUsersAsync(bool load)
|
||||||
@ -600,19 +643,31 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId);
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
if (user != null)
|
|
||||||
{
|
{
|
||||||
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
|
var user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId);
|
||||||
await logger.LogInformation("User Deleted {User}", UserRole.User);
|
if (user != null)
|
||||||
await LoadUsersAsync(true);
|
{
|
||||||
StateHasChanged();
|
user.IsDeleted = true;
|
||||||
|
await UserService.UpdateUserAsync(user);
|
||||||
|
await logger.LogInformation("User Soft Deleted {User}", user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var userrole = await UserRoleService.GetUserRoleAsync(UserRole.UserRoleId);
|
||||||
|
userrole.ExpiryDate = DateTime.UtcNow;
|
||||||
|
await UserRoleService.UpdateUserRoleAsync(userrole);
|
||||||
|
await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name);
|
||||||
|
}
|
||||||
|
AddModuleMessage(Localizer["Success.DeleteUser"], MessageType.Success);
|
||||||
|
await LoadUsersAsync(true);
|
||||||
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Deleting User {User} {Error}", UserRole.User, ex.Message);
|
await logger.LogError(ex, "Error Deleting User {User} {Error}", UserRole.User, ex.Message);
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
AddModuleMessage(Localizer["Error.DeleteUser"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,14 +680,16 @@ else
|
|||||||
await SiteService.UpdateSiteAsync(site);
|
await SiteService.UpdateSiteAsync(site);
|
||||||
|
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:AllowSiteLogin", _allowsitelogin, false);
|
|
||||||
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
|
settings = SettingService.SetSetting(settings, "LoginOptions:RegisterUrl", _registerurl, false);
|
||||||
|
settings = SettingService.SetSetting(settings, "LoginOptions:ProfileUrl", _profileurl, false);
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:TwoFactor", _twofactor, false);
|
settings = SettingService.SetSetting(settings, "LoginOptions:TwoFactor", _twofactor, false);
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:CookieName", _cookiename, true);
|
settings = SettingService.SetSetting(settings, "LoginOptions:CookieName", _cookiename, true);
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:CookieExpiration", _cookieexpiration, true);
|
settings = SettingService.SetSetting(settings, "LoginOptions:CookieExpiration", _cookieexpiration, true);
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:AlwaysRemember", _alwaysremember, false);
|
settings = SettingService.SetSetting(settings, "LoginOptions:AlwaysRemember", _alwaysremember, false);
|
||||||
|
settings = SettingService.SetSetting(settings, "LoginOptions:LogoutEverywhere", _logouteverywhere, false);
|
||||||
|
|
||||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequiredLength", _minimumlength, true);
|
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequiredLength", _minimumlength, true);
|
||||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", _uniquecharacters, true);
|
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", _uniquecharacters, true);
|
||||||
@ -666,9 +723,12 @@ else
|
|||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:RoleClaimMappings", _roleclaimmappings, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:RoleClaimMappings", _roleclaimmappings, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:SynchronizeRoles", _synchronizeroles, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:SynchronizeRoles", _synchronizeroles, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:ProfileClaimTypes", _profileclaimtypes, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:ProfileClaimTypes", _profileclaimtypes, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "ExternalLogin:SaveTokens", _savetokens, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:DomainFilter", _domainfilter, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:DomainFilter", _domainfilter, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:CreateUsers", _createusers, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:CreateUsers", _createusers, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:VerifyUsers", _verifyusers, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:VerifyUsers", _verifyusers, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "ExternalLogin:AllowHostRole", _allowhostrole, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "LoginOptions:AllowSiteLogin", _allowsitelogin, false);
|
||||||
|
|
||||||
settings = SettingService.SetSetting(settings, "JwtOptions:Secret", _secret, true);
|
settings = SettingService.SetSetting(settings, "JwtOptions:Secret", _secret, true);
|
||||||
settings = SettingService.SetSetting(settings, "JwtOptions:Issuer", _issuer, true);
|
settings = SettingService.SetSetting(settings, "JwtOptions:Issuer", _issuer, true);
|
||||||
@ -691,6 +751,10 @@ else
|
|||||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await ScrollToPageTop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProviderChanged(ChangeEventArgs e)
|
private void ProviderChanged(ChangeEventArgs e)
|
||||||
|
@ -53,17 +53,17 @@ else
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<Pager Items="@userroles">
|
<Pager Items="@userroles">
|
||||||
<Header>
|
<Header>
|
||||||
<th>@Localizer["Roles"]</th>
|
<th>@Localizer["Roles"]</th>
|
||||||
<th>@Localizer["Effective"]</th>
|
<th>@Localizer["Effective"]</th>
|
||||||
<th>@Localizer["Expiry"]</th>
|
<th>@Localizer["Expiry"]</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td>@context.Role.Name</td>
|
<td>@context.Role.Name</td>
|
||||||
<td>@Utilities.UtcAsLocalDate(context.EffectiveDate)</td>
|
<td>@Utilities.UtcAsLocalDate(context.EffectiveDate)</td>
|
||||||
<td>@Utilities.UtcAsLocalDate(context.ExpiryDate)</td>
|
<td>@Utilities.UtcAsLocalDate(context.ExpiryDate)</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || (context.Role.Name == RoleNames.Host && userid == PageState.User.UserId))" ResourceKey="DeleteUserRole" />
|
<ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.Name == RoleNames.Host && userid == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
|
||||||
</td>
|
</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
@ -171,8 +171,18 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
|
var userrole = await UserRoleService.GetUserRoleAsync(UserRoleId);
|
||||||
await logger.LogInformation("User Removed From Role {UserRoleId}", UserRoleId);
|
if (userrole.Role.Name == RoleNames.Registered)
|
||||||
|
{
|
||||||
|
userrole.ExpiryDate = DateTime.UtcNow;
|
||||||
|
await UserRoleService.UpdateUserRoleAsync(userrole);
|
||||||
|
await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
|
||||||
|
await logger.LogInformation("User {Username} Removed From Role {Role}", userrole.User.Username, userrole.Role.Name);
|
||||||
|
}
|
||||||
AddModuleMessage(Localizer["Success.User.Remove"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.User.Remove"], MessageType.Success);
|
||||||
await GetUserRoles();
|
await GetUserRoles();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
@ -101,8 +101,8 @@
|
|||||||
_url = visitor.Url;
|
_url = visitor.Url;
|
||||||
_referrer = visitor.Referrer;
|
_referrer = visitor.Referrer;
|
||||||
_visits = visitor.Visits.ToString();
|
_visits = visitor.Visits.ToString();
|
||||||
_visited = visitor.VisitedOn.ToString(CultureInfo.CurrentCulture);
|
_visited = UtcToLocal(visitor.VisitedOn).Value.ToString(CultureInfo.CurrentCulture);
|
||||||
_created = visitor.CreatedOn.ToString(CultureInfo.CurrentCulture);
|
_created = UtcToLocal(visitor.CreatedOn).Value.ToString(CultureInfo.CurrentCulture);
|
||||||
|
|
||||||
if (visitor.UserId != null)
|
if (visitor.UserId != null)
|
||||||
{
|
{
|
||||||
|
@ -53,8 +53,8 @@ else
|
|||||||
</td>
|
</td>
|
||||||
<td>@context.Language</td>
|
<td>@context.Language</td>
|
||||||
<td>@context.Visits</td>
|
<td>@context.Visits</td>
|
||||||
<td>@context.VisitedOn</td>
|
<td>@UtcToLocal(context.VisitedOn)</td>
|
||||||
<td>@context.CreatedOn</td>
|
<td>@UtcToLocal(context.CreatedOn)</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@ -100,6 +100,18 @@ else
|
|||||||
<br />
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
<TabPanel Name="Robots" Heading="Robots.txt" ResourceKey="Robots">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="robots" HelpText="Specify your robots.txt instructions to provide bots with guidance on which parts of your site should be indexed" ResourceKey="Robots">Instructions: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="robots" class="form-control" @bind="@_robots" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||||
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,6 +125,7 @@ else
|
|||||||
private string _filter = "";
|
private string _filter = "";
|
||||||
private int _retention = 30;
|
private int _retention = 30;
|
||||||
private string _correlation = "true";
|
private string _correlation = "true";
|
||||||
|
private string _robots = "";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
@ -139,7 +152,8 @@ else
|
|||||||
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
|
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
|
||||||
_retention = int.Parse(SettingService.GetSetting(settings, "VisitorRetention", "30"));
|
_retention = int.Parse(SettingService.GetSetting(settings, "VisitorRetention", "30"));
|
||||||
_correlation = SettingService.GetSetting(settings, "VisitorCorrelation", "true");
|
_correlation = SettingService.GetSetting(settings, "VisitorCorrelation", "true");
|
||||||
}
|
_robots = SettingService.GetSetting(settings, "Robots", "");
|
||||||
|
}
|
||||||
|
|
||||||
private async void TypeChanged(ChangeEventArgs e)
|
private async void TypeChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
@ -191,6 +205,7 @@ else
|
|||||||
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
|
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
|
||||||
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention.ToString(), true);
|
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention.ToString(), true);
|
||||||
settings = SettingService.SetSetting(settings, "VisitorCorrelation", _correlation, true);
|
settings = SettingService.SetSetting(settings, "VisitorCorrelation", _correlation, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "Robots", _robots, true);
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
|
|
||||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@if (!string.IsNullOrEmpty(Action))
|
@if (!string.IsNullOrEmpty(Action))
|
||||||
{
|
{
|
||||||
<button type="button" class="@Class" @onclick="Confirm">@((MarkupString)_iconSpan) @Text</button>
|
<button type="button" class="@ConfirmClass" @onclick="Confirm">@((MarkupString)_iconSpan) @Text</button>
|
||||||
}
|
}
|
||||||
<button type="button" class="btn btn-secondary" @onclick="DisplayModal">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="@CancelClass" @onclick="DisplayModal">@SharedLocalizer["Cancel"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -66,12 +66,12 @@ else
|
|||||||
{
|
{
|
||||||
<form method="post" @formname="@($"ActionDialogConfirmForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="Confirm" data-enhance>
|
<form method="post" @formname="@($"ActionDialogConfirmForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="Confirm" data-enhance>
|
||||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||||
<button type="submit" class="@Class">@((MarkupString)_iconSpan) @Text</button>
|
<button type="submit" class="@ConfirmClass">@((MarkupString)_iconSpan) @Text</button>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
<form method="post" @formname="@($"ActionDialogCancelForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="DisplayModal" data-enhance>
|
<form method="post" @formname="@($"ActionDialogCancelForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="DisplayModal" data-enhance>
|
||||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||||
<button type="submit" class="btn btn-secondary">@SharedLocalizer["Cancel"]</button>
|
<button type="submit" class="@CancelClass">@SharedLocalizer["Cancel"]</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -128,6 +128,12 @@ else
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string Class { get; set; } // optional
|
public string Class { get; set; } // optional
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string ConfirmClass { get; set; } // optional - for Confirm modal button
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string CancelClass { get; set; } // optional - for Cancel modal button
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Disabled { get; set; } // optional
|
public bool Disabled { get; set; } // optional
|
||||||
|
|
||||||
@ -168,6 +174,16 @@ else
|
|||||||
Class = "btn btn-success";
|
Class = "btn btn-success";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(ConfirmClass))
|
||||||
|
{
|
||||||
|
ConfirmClass = Class;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(CancelClass))
|
||||||
|
{
|
||||||
|
CancelClass = "btn btn-secondary";
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(EditMode))
|
if (!string.IsNullOrEmpty(EditMode))
|
||||||
{
|
{
|
||||||
_editmode = bool.Parse(EditMode);
|
_editmode = bool.Parse(EditMode);
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
if (CreatedOn != null)
|
if (CreatedOn != null)
|
||||||
{
|
{
|
||||||
_text += $" {Localizer["On"]} <b>{CreatedOn.Value.ToString(DateTimeFormat)}</b>";
|
_text += $" {Localizer["On"]} <b>{UtcToLocal(CreatedOn).Value.ToString(DateTimeFormat)}</ b >";
|
||||||
}
|
}
|
||||||
|
|
||||||
_text += "</p>";
|
_text += "</p>";
|
||||||
@ -69,7 +69,7 @@
|
|||||||
|
|
||||||
if (ModifiedOn != null)
|
if (ModifiedOn != null)
|
||||||
{
|
{
|
||||||
_text += $" {Localizer["On"]} <b>{ModifiedOn.Value.ToString(DateTimeFormat)}</b>";
|
_text += $" {Localizer["On"]} <b>{UtcToLocal(ModifiedOn).Value.ToString(DateTimeFormat)}</ b >";
|
||||||
}
|
}
|
||||||
|
|
||||||
_text += "</p>";
|
_text += "</p>";
|
||||||
@ -86,7 +86,7 @@
|
|||||||
|
|
||||||
if (DeletedOn != null)
|
if (DeletedOn != null)
|
||||||
{
|
{
|
||||||
_text += $" {Localizer["On"]} <b>{DeletedOn.Value.ToString(DateTimeFormat)}</b>";
|
_text += $" {Localizer["On"]} <b>{UtcToLocal(DeletedOn).Value.ToString(DateTimeFormat)}</ b >";
|
||||||
}
|
}
|
||||||
|
|
||||||
_text += "</p>";
|
_text += "</p>";
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
@inherits ModuleControlBase
|
@inherits ModuleControlBase
|
||||||
@inject IFolderService FolderService
|
@inject IFolderService FolderService
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@inject ISettingService SettingService
|
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
|
@inject ISettingService SettingService
|
||||||
@inject IStringLocalizer<FileManager> Localizer
|
@inject IStringLocalizer<FileManager> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@ -157,9 +157,19 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int ChunkSize { get; set; } = 1; // optional - size of file chunks to upload in MB
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<int> OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded
|
public EventCallback<int> OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<int> OnSelectFolder { get; set; } // optional - executes a method in the calling component when a folder is selected
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<int> OnSelectFile { get; set; } // optional - executes a method in the calling component when a file is selected
|
||||||
|
|
||||||
|
[Obsolete("Use OnSelectFile instead.")]
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<int> OnSelect { get; set; } // optional - executes a method in the calling component when a file is selected
|
public EventCallback<int> OnSelect { get; set; } // optional - executes a method in the calling component when a file is selected
|
||||||
|
|
||||||
@ -196,7 +206,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
FolderId = -1;
|
FolderId = -1;
|
||||||
_message = "Folder Path " + Folder + "Does Not Exist";
|
_message = "Folder Path " + Folder + " Does Not Exist";
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,9 +236,9 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FileId = -1; // file does not exist
|
_message = "FileId " + FileId.ToString() + " Does Not Exist";
|
||||||
_message = "FileId " + FileId.ToString() + "Does Not Exist";
|
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
|
FileId = -1; // file does not exist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,6 +307,8 @@
|
|||||||
FileId = -1;
|
FileId = -1;
|
||||||
_file = null;
|
_file = null;
|
||||||
_image = string.Empty;
|
_image = string.Empty;
|
||||||
|
|
||||||
|
await OnSelectFolder.InvokeAsync(FolderId);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -312,7 +324,10 @@
|
|||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
FileId = int.Parse((string)e.Value);
|
FileId = int.Parse((string)e.Value);
|
||||||
await SetImage();
|
await SetImage();
|
||||||
|
#pragma warning disable CS0618
|
||||||
await OnSelect.InvokeAsync(FileId);
|
await OnSelect.InvokeAsync(FileId);
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
await OnSelectFile.InvokeAsync(FileId);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,6 +374,8 @@
|
|||||||
}
|
}
|
||||||
if (restricted == "")
|
if (restricted == "")
|
||||||
{
|
{
|
||||||
|
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// upload the files
|
// upload the files
|
||||||
@ -377,57 +394,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var chunksize = ChunkSize;
|
||||||
|
if (chunksize == 1)
|
||||||
|
{
|
||||||
|
// if ChunkSize parameter is not overridden use the site setting
|
||||||
|
chunksize = int.Parse(SettingService.GetSetting(PageState.Site.Settings, "MaxChunkSize", "1"));
|
||||||
|
}
|
||||||
|
|
||||||
if (!ShowProgress)
|
if (!ShowProgress)
|
||||||
{
|
{
|
||||||
_uploading = true;
|
_uploading = true;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken, jwt);
|
// upload files
|
||||||
|
var success = await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken, jwt, chunksize, tokenSource.Token);
|
||||||
// uploading is asynchronous so we need to poll to determine if uploads are completed
|
|
||||||
var success = true;
|
|
||||||
int upload = 0;
|
|
||||||
while (upload < uploads.Length && success)
|
|
||||||
{
|
|
||||||
success = false;
|
|
||||||
var filename = uploads[upload].Split(':')[0];
|
|
||||||
|
|
||||||
var size = Int64.Parse(uploads[upload].Split(':')[1]); // bytes
|
|
||||||
var megabits = (size / 1048576.0) * 8; // binary conversion
|
|
||||||
var uploadspeed = (PageState.Alias.Name.Contains("localhost")) ? 100 : 3; // 3 Mbps is FCC minimum for broadband upload
|
|
||||||
var uploadtime = (megabits / uploadspeed); // seconds
|
|
||||||
var maxattempts = 5; // polling (minimum timeout duration will be 5 seconds)
|
|
||||||
var sleep = (int)Math.Ceiling(uploadtime / maxattempts) * 1000; // milliseconds
|
|
||||||
|
|
||||||
int attempts = 0;
|
|
||||||
while (attempts < maxattempts && !success)
|
|
||||||
{
|
|
||||||
attempts += 1;
|
|
||||||
Thread.Sleep(sleep);
|
|
||||||
|
|
||||||
if (Folder == Constants.PackagesFolder)
|
|
||||||
{
|
|
||||||
var files = await FileService.GetFilesAsync(folder);
|
|
||||||
if (files != null && files.Any(item => item.Name == filename))
|
|
||||||
{
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var file = await FileService.GetFileAsync(int.Parse(folder), filename);
|
|
||||||
if (file != null)
|
|
||||||
{
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
upload++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset progress indicators
|
// reset progress indicators
|
||||||
if (ShowProgress)
|
if (ShowProgress)
|
||||||
@ -452,7 +433,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await logger.LogInformation("File Upload Failed Or Is Still In Progress {Files}", uploads);
|
await logger.LogError("File Upload Failed {Files}", uploads);
|
||||||
_message = Localizer["Error.File.Upload"];
|
_message = Localizer["Error.File.Upload"];
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
@ -469,7 +450,10 @@
|
|||||||
{
|
{
|
||||||
FileId = file.FileId;
|
FileId = file.FileId;
|
||||||
await SetImage();
|
await SetImage();
|
||||||
|
#pragma warning disable CS0618
|
||||||
await OnSelect.InvokeAsync(FileId);
|
await OnSelect.InvokeAsync(FileId);
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
await OnSelectFile.InvokeAsync(FileId);
|
||||||
await OnUpload.InvokeAsync(FileId);
|
await OnUpload.InvokeAsync(FileId);
|
||||||
}
|
}
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
@ -482,6 +466,10 @@
|
|||||||
_message = Localizer["Error.File.Upload"];
|
_message = Localizer["Error.File.Upload"];
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
_uploading = false;
|
_uploading = false;
|
||||||
|
await tokenSource.CancelAsync();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
tokenSource.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -516,7 +504,10 @@
|
|||||||
await GetFiles();
|
await GetFiles();
|
||||||
FileId = -1;
|
FileId = -1;
|
||||||
await SetImage();
|
await SetImage();
|
||||||
|
#pragma warning disable CS0618
|
||||||
await OnSelect.InvokeAsync(FileId);
|
await OnSelect.InvokeAsync(FileId);
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
await OnSelectFile.InvokeAsync(FileId);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@ -84,7 +84,7 @@
|
|||||||
|
|
||||||
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@ -200,7 +200,7 @@
|
|||||||
{
|
{
|
||||||
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Interactive)
|
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Interactive)
|
||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@ -248,7 +248,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@ -368,6 +368,12 @@
|
|||||||
[SupplyParameterFromForm(FormName = "PagerForm")]
|
[SupplyParameterFromForm(FormName = "PagerForm")]
|
||||||
public string _Search { get => ""; set => _search = value; }
|
public string _Search { get => ""; set => _search = value; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Accepted values are Start or Center or End. The default value is Center
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public string PaginationAlignment { get; set; } = "center"; // Alignment of the Page Numbering start, center, end
|
||||||
|
|
||||||
private IEnumerable<TableItem> ItemList { get; set; }
|
private IEnumerable<TableItem> ItemList { get; set; }
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
@foreach (User user in _users)
|
@foreach (User user in _users)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td>@user.DisplayName</td>
|
<td>@user.DisplayName (@user.Username)</td>
|
||||||
@foreach (var permissionname in _permissionnames)
|
@foreach (var permissionname in _permissionnames)
|
||||||
{
|
{
|
||||||
<td style="text-align: center; width: 1px;">
|
<td style="text-align: center; width: 1px;">
|
||||||
@ -270,8 +270,8 @@
|
|||||||
private async Task<Dictionary<string, string>> GetUsers(string filter)
|
private async Task<Dictionary<string, string>> GetUsers(string filter)
|
||||||
{
|
{
|
||||||
var users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
var users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||||
return users.Where(item => item.User.DisplayName.Contains(filter, StringComparison.OrdinalIgnoreCase))
|
return users.Where(item => item.User.DisplayName.Contains(filter, StringComparison.OrdinalIgnoreCase) || item.User.Username.Contains(filter, StringComparison.OrdinalIgnoreCase))
|
||||||
.ToDictionary(item => item.UserId.ToString(), item => item.User.DisplayName);
|
.ToDictionary(item => item.UserId.ToString(), item => item.User.DisplayName + " (" + item.User.Username + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddUser()
|
private async Task AddUser()
|
||||||
|
@ -277,7 +277,7 @@
|
|||||||
{
|
{
|
||||||
// include CSS theme
|
// include CSS theme
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
await interop.IncludeLink("", "stylesheet", $"css/quill/quill.{_theme}.css", "text/css", "", "", "");
|
await interop.IncludeLink("", "stylesheet", $"{PageState?.Alias.BaseUrl}/css/quill/quill.{_theme}.css", "text/css", "", "", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
@ -36,14 +36,7 @@ else
|
|||||||
|
|
||||||
Parent.AddTabPanel((TabPanel)this);
|
Parent.AddTabPanel((TabPanel)this);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(Heading))
|
Heading = string.IsNullOrEmpty(Heading) ? Localize(nameof(Name), Name) : Localize(nameof(Heading), Heading);
|
||||||
{
|
|
||||||
Heading = Localize(nameof(Name), Name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Heading = Localize(nameof(Heading), Heading);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string DisplayHeading()
|
public string DisplayHeading()
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
@namespace Oqtane.Modules.HtmlText
|
@namespace Oqtane.Modules.HtmlText
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject IHtmlTextService HtmlTextService
|
@inject IHtmlTextService HtmlTextService
|
||||||
|
@inject ISettingService SettingService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
|
||||||
@if (PageState.EditMode)
|
@if (PageState.EditMode)
|
||||||
@ -36,6 +37,10 @@
|
|||||||
{
|
{
|
||||||
content = htmltext.Content;
|
content = htmltext.Content;
|
||||||
content = Utilities.FormatContent(content, PageState.Alias, "render");
|
content = Utilities.FormatContent(content, PageState.Alias, "render");
|
||||||
|
if (bool.Parse(SettingService.GetSetting(ModuleState.Settings, "DynamicTokens", "false")))
|
||||||
|
{
|
||||||
|
content = ReplaceTokens(content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ namespace Oqtane.Modules.HtmlText
|
|||||||
Version = "1.0.1",
|
Version = "1.0.1",
|
||||||
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
|
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
|
||||||
ReleaseVersions = "1.0.0,1.0.1",
|
ReleaseVersions = "1.0.0,1.0.1",
|
||||||
SettingsType = string.Empty,
|
SettingsType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client",
|
||||||
Resources = new List<Resource>()
|
Resources = new List<Resource>()
|
||||||
{
|
{
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Module.css" }
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Module.css" }
|
||||||
|
55
Oqtane.Client/Modules/HtmlText/Settings.razor
Normal file
55
Oqtane.Client/Modules/HtmlText/Settings.razor
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
@namespace Oqtane.Modules.HtmlText
|
||||||
|
@inherits ModuleBase
|
||||||
|
@inject ISettingService SettingService
|
||||||
|
@implements Oqtane.Interfaces.ISettingsControl
|
||||||
|
@inject IStringLocalizer<Settings> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="dynamictokens" ResourceKey="DynamicTokens" ResourceType="@resourceType" HelpText="Do you wish to allow tokens to be dynamically replaced? Please note that this will affect the performance of your site.">Dynamic Tokens? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="dynamictokens" class="form-select" @bind="@_dynamictokens">
|
||||||
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private string resourceType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"; // for localization
|
||||||
|
|
||||||
|
private ElementReference form;
|
||||||
|
private bool validated = false;
|
||||||
|
|
||||||
|
private string _dynamictokens;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_dynamictokens = SettingService.GetSetting(ModuleState.Settings, "DynamicTokens", "false");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||||
|
settings = SettingService.SetSetting(settings, "DynamicTokens", _dynamictokens);
|
||||||
|
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +1,25 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
using Oqtane.Shared;
|
|
||||||
using Oqtane.Models;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Oqtane.Services;
|
|
||||||
using System;
|
using System;
|
||||||
using Oqtane.Enums;
|
|
||||||
using Oqtane.UI;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.JSInterop;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Dynamic;
|
using System.Dynamic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
|
using Oqtane.Enums;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Services;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
using Oqtane.UI;
|
||||||
|
|
||||||
namespace Oqtane.Modules
|
namespace Oqtane.Modules
|
||||||
{
|
{
|
||||||
public abstract class ModuleBase : ComponentBase, IModuleControl
|
public abstract class ModuleBase : ComponentBase, IModuleControl
|
||||||
{
|
{
|
||||||
private Logger _logger;
|
private Logger _logger;
|
||||||
private string _urlparametersstate;
|
private string _urlparametersstate = string.Empty;
|
||||||
private Dictionary<string, string> _urlparameters;
|
private Dictionary<string, string> _urlparameters;
|
||||||
|
private bool _scriptsloaded = false;
|
||||||
|
|
||||||
protected Logger logger => _logger ?? (_logger = new Logger(this));
|
protected Logger logger => _logger ?? (_logger = new Logger(this));
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ namespace Oqtane.Modules
|
|||||||
protected PageState PageState { get; set; }
|
protected PageState PageState { get; set; }
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
protected Module ModuleState { get; set; }
|
protected Models.Module ModuleState { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public RenderModeBoundary RenderModeBoundary { get; set; }
|
public RenderModeBoundary RenderModeBoundary { get; set; }
|
||||||
@ -60,7 +62,7 @@ namespace Oqtane.Modules
|
|||||||
public Dictionary<string, string> UrlParameters {
|
public Dictionary<string, string> UrlParameters {
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_urlparametersstate == null || _urlparametersstate != PageState.UrlParameters)
|
if (string.IsNullOrEmpty(_urlparametersstate) || _urlparametersstate != PageState.UrlParameters)
|
||||||
{
|
{
|
||||||
_urlparametersstate = PageState.UrlParameters;
|
_urlparametersstate = PageState.UrlParameters;
|
||||||
_urlparameters = GetUrlParameters(UrlParametersTemplate);
|
_urlparameters = GetUrlParameters(UrlParametersTemplate);
|
||||||
@ -77,18 +79,21 @@ namespace Oqtane.Modules
|
|||||||
{
|
{
|
||||||
List<Resource> resources = null;
|
List<Resource> resources = null;
|
||||||
var type = GetType();
|
var type = GetType();
|
||||||
if (type.BaseType == typeof(ModuleBase))
|
if (type.IsSubclassOf(typeof(ModuleBase)))
|
||||||
{
|
{
|
||||||
if (PageState.Page.Resources != null)
|
if (type.IsSubclassOf(typeof(ModuleControlBase)))
|
||||||
{
|
{
|
||||||
resources = PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Script && item.Level == ResourceLevel.Module && item.Namespace == type.Namespace).ToList();
|
if (Resources != null)
|
||||||
|
{
|
||||||
|
resources = Resources.Where(item => item.ResourceType == ResourceType.Script).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else // ModuleBase
|
||||||
else // modulecontrolbase
|
|
||||||
{
|
|
||||||
if (Resources != null)
|
|
||||||
{
|
{
|
||||||
resources = Resources.Where(item => item.ResourceType == ResourceType.Script).ToList();
|
if (PageState.Page.Resources != null)
|
||||||
|
{
|
||||||
|
resources = PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Script && item.Level == ResourceLevel.Module && item.Namespace == type.Namespace).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (resources != null && resources.Any())
|
if (resources != null && resources.Any())
|
||||||
@ -103,12 +108,12 @@ namespace Oqtane.Modules
|
|||||||
if (!string.IsNullOrEmpty(resource.Url))
|
if (!string.IsNullOrEmpty(resource.Url))
|
||||||
{
|
{
|
||||||
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
||||||
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module, location = resource.Location.ToString().ToLower() });
|
scripts.Add(new { href = url, type = resource.Type ?? "", bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", location = resource.Location.ToString().ToLower(), dataAttributes = resource.DataAttributes });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inline += 1;
|
inline += 1;
|
||||||
await interop.IncludeScript(GetType().Namespace.ToLower() + inline.ToString(), "", "", "", resource.Content, resource.Location.ToString().ToLower());
|
await interop.IncludeScript(GetType().Namespace.ToLower() + inline.ToString(), "", "", "", resource.Type ?? "", resource.Content, resource.Location.ToString().ToLower());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,6 +122,7 @@ namespace Oqtane.Modules
|
|||||||
await interop.IncludeScripts(scripts.ToArray());
|
await interop.IncludeScripts(scripts.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_scriptsloaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +131,14 @@ namespace Oqtane.Modules
|
|||||||
return PageState?.RenderId == ModuleState?.RenderId;
|
return PageState?.RenderId == ModuleState?.RenderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ScriptsLoaded
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _scriptsloaded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// path method
|
// path method
|
||||||
|
|
||||||
public string ModulePath()
|
public string ModulePath()
|
||||||
@ -132,6 +146,15 @@ namespace Oqtane.Modules
|
|||||||
return PageState?.Alias.BaseUrl + "/Modules/" + GetType().Namespace + "/";
|
return PageState?.Alias.BaseUrl + "/Modules/" + GetType().Namespace + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fingerprint hash code for static assets
|
||||||
|
public string Fingerprint
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ModuleState.ModuleDefinition.Fingerprint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// url methods
|
// url methods
|
||||||
|
|
||||||
// navigate url
|
// navigate url
|
||||||
@ -394,6 +417,118 @@ namespace Oqtane.Modules
|
|||||||
await interop.ScrollTo(0, 0, "smooth");
|
await interop.ScrollTo(0, 0, "smooth");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ReplaceTokens(string content)
|
||||||
|
{
|
||||||
|
return ReplaceTokens(content, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ReplaceTokens(string content, object obj)
|
||||||
|
{
|
||||||
|
// Using StringBuilder avoids the performance penalty of repeated string allocations
|
||||||
|
// that occur with string.Replace or string concatenation inside loops.
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var cache = new Dictionary<string, string>(); // Cache to store resolved tokens
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
// Loop through content to find and replace all tokens
|
||||||
|
while (index < content.Length)
|
||||||
|
{
|
||||||
|
int start = content.IndexOf('[', index); // Find start of token
|
||||||
|
if (start == -1)
|
||||||
|
{
|
||||||
|
sb.Append(content, index, content.Length - index); // Append remaining content
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = content.IndexOf(']', start); // Find end of token
|
||||||
|
if (end == -1)
|
||||||
|
{
|
||||||
|
sb.Append(content, index, content.Length - index); // Append unmatched content
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(content, index, start - index); // Append content before token
|
||||||
|
|
||||||
|
string token = content.Substring(start + 1, end - start - 1); // Extract token without brackets
|
||||||
|
string[] parts = token.Split('|', 2); // Separate default fallback if present
|
||||||
|
string key = parts[0];
|
||||||
|
string fallback = parts.Length == 2 ? parts[1] : null;
|
||||||
|
|
||||||
|
if (!cache.TryGetValue(token, out string replacement)) // Check cache first
|
||||||
|
{
|
||||||
|
replacement = "[" + token + "]"; // Default replacement is original token
|
||||||
|
string[] segments = key.Split(':');
|
||||||
|
|
||||||
|
if (segments.Length >= 2)
|
||||||
|
{
|
||||||
|
object current = GetTarget(segments[0], obj); // Start from root object
|
||||||
|
for (int i = 1; i < segments.Length && current != null; i++)
|
||||||
|
{
|
||||||
|
var type = current.GetType();
|
||||||
|
var prop = type.GetProperty(segments[i]);
|
||||||
|
current = prop?.GetValue(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current != null)
|
||||||
|
{
|
||||||
|
replacement = current.ToString();
|
||||||
|
}
|
||||||
|
else if (fallback != null)
|
||||||
|
{
|
||||||
|
replacement = fallback; // Use fallback if available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache[token] = replacement; // Store in cache
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(replacement); // Append replacement value
|
||||||
|
index = end + 1; // Move index past token
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the object instance for a given object name
|
||||||
|
// Easy to extend with additional object types
|
||||||
|
private object GetTarget(string name, object obj)
|
||||||
|
{
|
||||||
|
return name switch
|
||||||
|
{
|
||||||
|
"ModuleState" => ModuleState,
|
||||||
|
"PageState" => PageState,
|
||||||
|
_ => (obj != null && obj.GetType().Name == name) ? obj : null // Fallback to obj
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// date methods
|
||||||
|
public DateTime? UtcToLocal(DateTime? datetime)
|
||||||
|
{
|
||||||
|
TimeZoneInfo timezone = null;
|
||||||
|
if (PageState.User != null && !string.IsNullOrEmpty(PageState.User.TimeZoneId))
|
||||||
|
{
|
||||||
|
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.User.TimeZoneId);
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(PageState.Site.TimeZoneId))
|
||||||
|
{
|
||||||
|
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.Site.TimeZoneId);
|
||||||
|
}
|
||||||
|
return Utilities.UtcAsLocalDateTime(datetime, timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime? LocalToUtc(DateTime? datetime)
|
||||||
|
{
|
||||||
|
TimeZoneInfo timezone = null;
|
||||||
|
if (PageState.User != null && !string.IsNullOrEmpty(PageState.User.TimeZoneId))
|
||||||
|
{
|
||||||
|
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.User.TimeZoneId);
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(PageState.Site.TimeZoneId))
|
||||||
|
{
|
||||||
|
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.Site.TimeZoneId);
|
||||||
|
}
|
||||||
|
return Utilities.LocalDateAndTimeAsUtc(datetime, timezone);
|
||||||
|
}
|
||||||
|
|
||||||
// logging methods
|
// logging methods
|
||||||
public async Task Log(Alias alias, LogLevel level, string function, Exception exception, string message, params object[] args)
|
public async Task Log(Alias alias, LogLevel level, string function, Exception exception, string message, params object[] args)
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>5.2.4</Version>
|
<Version>6.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
@ -22,17 +22,22 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.5" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.10" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.5" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
|
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="Installer\Controls\AzureSqlConfig.razor">
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PublishTrimmed>false</PublishTrimmed>
|
<PublishTrimmed>false</PublishTrimmed>
|
||||||
<BlazorEnableCompression>false</BlazorEnableCompression>
|
<BlazorEnableCompression>false</BlazorEnableCompression>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
@ -13,13 +12,13 @@ using System.Text.Json;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
using Microsoft.AspNetCore.Localization;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
|
using Oqtane.Shared;
|
||||||
using Oqtane.UI;
|
using Oqtane.UI;
|
||||||
|
|
||||||
namespace Oqtane.Client
|
namespace Oqtane.Client
|
||||||
@ -258,7 +257,7 @@ namespace Oqtane.Client
|
|||||||
var jsRuntime = serviceProvider.GetRequiredService<IJSRuntime>();
|
var jsRuntime = serviceProvider.GetRequiredService<IJSRuntime>();
|
||||||
var interop = new Interop(jsRuntime);
|
var interop = new Interop(jsRuntime);
|
||||||
var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName);
|
var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName);
|
||||||
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICultures?[0].Value;
|
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICulture.Name;
|
||||||
var localizationService = serviceProvider.GetRequiredService<ILocalizationService>();
|
var localizationService = serviceProvider.GetRequiredService<ILocalizationService>();
|
||||||
var cultures = await localizationService.GetCulturesAsync(false);
|
var cultures = await localizationService.GetCulturesAsync(false);
|
||||||
|
|
||||||
|
@ -8,20 +8,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"IIS Express": {
|
"Oqtane": {
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Oqtane.Client": {
|
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://localhost:44358/"
|
"applicationUrl": "http://localhost:44358/"
|
||||||
|
},
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -121,7 +121,7 @@
|
|||||||
<value>Server:</value>
|
<value>Server:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Server.HelpText" xml:space="preserve">
|
<data name="Server.HelpText" xml:space="preserve">
|
||||||
<value>Enter the database server name. This might include a port number as well if you are using a cloud service (ie. servername.database.windows.net,1433) </value>
|
<value>Enter the database server name. This might include a port number as well if you are using a cloud service.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Database.Text" xml:space="preserve">
|
<data name="Database.Text" xml:space="preserve">
|
||||||
<value>Database:</value>
|
<value>Database:</value>
|
||||||
|
@ -183,4 +183,13 @@
|
|||||||
<data name="Template" xml:space="preserve">
|
<data name="Template" xml:space="preserve">
|
||||||
<value>Select a site template</value>
|
<value>Select a site template</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Message.Username.Invalid" xml:space="preserve">
|
||||||
|
<value>The Username Provided Does Not Meet The System Requirement, It Can Only Contains Letters Or Digits.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Name.Text" xml:space="preserve">
|
||||||
|
<value>Full Name:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Name.HelpText" xml:space="preserve">
|
||||||
|
<value>Provide the full name of the host user</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -135,9 +135,6 @@
|
|||||||
<data name="Error.Folder.Save" xml:space="preserve">
|
<data name="Error.Folder.Save" xml:space="preserve">
|
||||||
<value>Error Saving Folder</value>
|
<value>Error Saving Folder</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Folder.Files.InvalidDelete" xml:space="preserve">
|
|
||||||
<value>Folder Has Files And Cannot Be Deleted</value>
|
|
||||||
</data>
|
|
||||||
<data name="Message.Folder.Subfolders.InvalidDelete" xml:space="preserve">
|
<data name="Message.Folder.Subfolders.InvalidDelete" xml:space="preserve">
|
||||||
<value>Folder Has Subfolders And Cannot Be Deleted</value>
|
<value>Folder Has Subfolders And Cannot Be Deleted</value>
|
||||||
</data>
|
</data>
|
||||||
@ -175,7 +172,7 @@
|
|||||||
<value>Capacity:</value>
|
<value>Capacity:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ImageSizes.HelpText" xml:space="preserve">
|
<data name="ImageSizes.HelpText" xml:space="preserve">
|
||||||
<value>Enter a list of image sizes which can be generated dynamically from uploaded images (ie. 200x200,400x400). Use * to indicate the folder supports all image sizes.</value>
|
<value>Optionally enter a list of image sizes which can be generated dynamically from uploaded images (ie. 200x200,400x400). Use * to indicate the folder supports all image sizes (not recommended).</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ImageSizes.Text" xml:space="preserve">
|
<data name="ImageSizes.Text" xml:space="preserve">
|
||||||
<value>Image Sizes:</value>
|
<value>Image Sizes:</value>
|
||||||
@ -198,4 +195,10 @@
|
|||||||
<data name="Settings.Heading" xml:space="preserve">
|
<data name="Settings.Heading" xml:space="preserve">
|
||||||
<value>Settings</value>
|
<value>Settings</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CacheControl.Text" xml:space="preserve">
|
||||||
|
<value>Caching:</value>
|
||||||
|
</data>
|
||||||
|
<data name="CacheControl.HelpText" xml:space="preserve">
|
||||||
|
<value>Optionally provide a Cache-Control directive for this folder. For example 'public, max-age=60' indicates that files in this folder should be cached for 60 seconds. Please note that when caching is enabled, changes to files will not be immediately reflected in the UI.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -165,4 +165,31 @@
|
|||||||
<data name="UploadFiles.Text" xml:space="preserve">
|
<data name="UploadFiles.Text" xml:space="preserve">
|
||||||
<value>Upload Files</value>
|
<value>Upload Files</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Files.Heading" xml:space="preserve">
|
||||||
|
<value>Files</value>
|
||||||
|
</data>
|
||||||
|
<data name="ImageExtensions.Text" xml:space="preserve">
|
||||||
|
<value>Image Extensions:</value>
|
||||||
|
</data>
|
||||||
|
<data name="ImageExtensions.HelpText" xml:space="preserve">
|
||||||
|
<value>Enter a comma separated list of image file extensions</value>
|
||||||
|
</data>
|
||||||
|
<data name="UploadableFileExtensions.Text" xml:space="preserve">
|
||||||
|
<value>Uploadable File Extensions:</value>
|
||||||
|
</data>
|
||||||
|
<data name="UploadableFileExtensions.HelpText" xml:space="preserve">
|
||||||
|
<value>Enter a comma separated list of uploadable file extensions</value>
|
||||||
|
</data>
|
||||||
|
<data name="MaxChunkSize.Text" xml:space="preserve">
|
||||||
|
<value>Max Upload Chunk Size (MB):</value>
|
||||||
|
</data>
|
||||||
|
<data name="MaxChunkSize.HelpText" xml:space="preserve">
|
||||||
|
<value>Files are split into chunks to streamline the upload process. Specify the maximum chunk size in MB (note that higher chunk sizes should only be used on faster networks).</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||||
|
<value>Settings Saved Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||||
|
<value>Error Saving Settings</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -180,9 +180,6 @@
|
|||||||
<data name="Once" xml:space="preserve">
|
<data name="Once" xml:space="preserve">
|
||||||
<value>Execute Once</value>
|
<value>Execute Once</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.NoJobs" xml:space="preserve">
|
|
||||||
<value>Please Note That After An Initial Installation You Must <a href={0}>Restart</a> The Application In Order To Activate The Default Scheduled Jobs.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Refresh.Text" xml:space="preserve">
|
<data name="Refresh.Text" xml:space="preserve">
|
||||||
<value>Refresh</value>
|
<value>Refresh</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -121,10 +121,10 @@
|
|||||||
<value>Forgot Password</value>
|
<value>Forgot Password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Account.Verified" xml:space="preserve">
|
<data name="Success.Account.Verified" xml:space="preserve">
|
||||||
<value>User Account Verified Successfully. You Can Now Login With Your Username And Password Below.</value>
|
<value>User Account Email Address Verified Successfully. You Can Now Login With Your Username And Password.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Account.NotVerified" xml:space="preserve">
|
<data name="Message.Account.NotVerified" xml:space="preserve">
|
||||||
<value>User Account Could Not Be Verified. Please Contact Your Administrator For Further Instructions.</value>
|
<value>User Account Email Address Could Not Be Verified. Please Contact Your Administrator For Further Instructions.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Account.Linked" xml:space="preserve">
|
<data name="Success.Account.Linked" xml:space="preserve">
|
||||||
<value>User Account Linked Successfully. You Can Now Login With Your External Login Below.</value>
|
<value>User Account Linked Successfully. You Can Now Login With Your External Login Below.</value>
|
||||||
@ -133,7 +133,7 @@
|
|||||||
<value>External Login Could Not Be Linked. Please Contact Your Administrator For Further Instructions.</value>
|
<value>External Login Could Not Be Linked. Please Contact Your Administrator For Further Instructions.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Login.Fail" xml:space="preserve">
|
<data name="Error.Login.Fail" xml:space="preserve">
|
||||||
<value>Login Failed. Please Remember That Passwords Are Case Sensitive. If You Have Attempted To Sign In Multiple Times Unsuccessfully, Your Account Will Be Locked Out For A Period Of Time. Note That User Accounts Require Verification When They Are Initially Created So You May Wish To Check Your Email If You Are A New User.</value>
|
<value>Login Failed. Please Remember That Passwords Are Case Sensitive. If You Have Attempted To Sign In Multiple Times Unsuccessfully, Your Account Will Be Locked Out For A Period Of Time. Note That User Accounts Often Require Email Address Verification So You May Wish To Check Your Email For A Notification.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Required.UserInfo" xml:space="preserve">
|
<data name="Message.Required.UserInfo" xml:space="preserve">
|
||||||
<value>Please Provide All Required Fields</value>
|
<value>Please Provide All Required Fields</value>
|
||||||
|
@ -147,8 +147,8 @@
|
|||||||
<data name="Owner.HelpText" xml:space="preserve">
|
<data name="Owner.HelpText" xml:space="preserve">
|
||||||
<value>The owner or creator of the module</value>
|
<value>The owner or creator of the module</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ReferenceUrl.HelpText" xml:space="preserve">
|
<data name="Url.HelpText" xml:space="preserve">
|
||||||
<value>The reference url of the module</value>
|
<value>The url of the module</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Contact.HelpText" xml:space="preserve">
|
<data name="Contact.HelpText" xml:space="preserve">
|
||||||
<value>The contact for the module</value>
|
<value>The contact for the module</value>
|
||||||
@ -171,8 +171,8 @@
|
|||||||
<data name="Owner.Text" xml:space="preserve">
|
<data name="Owner.Text" xml:space="preserve">
|
||||||
<value>Owner: </value>
|
<value>Owner: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ReferenceUrl.Text" xml:space="preserve">
|
<data name="Url.Text" xml:space="preserve">
|
||||||
<value>Reference Url: </value>
|
<value>Url: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Contact.Text" xml:space="preserve">
|
<data name="Contact.Text" xml:space="preserve">
|
||||||
<value>Contact: </value>
|
<value>Contact: </value>
|
||||||
@ -228,18 +228,6 @@
|
|||||||
<data name="View License" xml:space="preserve">
|
<data name="View License" xml:space="preserve">
|
||||||
<value>View License</value>
|
<value>View License</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Validate" xml:space="preserve">
|
|
||||||
<value>Error Validating Package</value>
|
|
||||||
</data>
|
|
||||||
<data name="Message.Download" xml:space="preserve">
|
|
||||||
<value>Package Version Has Been Verified. Please Select The Download Button To Obtain The Package.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Message.Validate" xml:space="preserve">
|
|
||||||
<value>This Package Version Has Not Been Registered In The Oqtane Marketplace Or You Do Not Have The Right To Use It From This Installation</value>
|
|
||||||
</data>
|
|
||||||
<data name="Validate" xml:space="preserve">
|
|
||||||
<value>Validate</value>
|
|
||||||
</data>
|
|
||||||
<data name="Browse" xml:space="preserve">
|
<data name="Browse" xml:space="preserve">
|
||||||
<value>Browse</value>
|
<value>Browse</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -159,4 +159,13 @@
|
|||||||
<data name="Enabled" xml:space="preserve">
|
<data name="Enabled" xml:space="preserve">
|
||||||
<value>Enabled?</value>
|
<value>Enabled?</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Synchronize" xml:space="preserve">
|
||||||
|
<value>Check For Updates</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Module.Synchronize" xml:space="preserve">
|
||||||
|
<value>Module Information Has Been Retrieved From The Marketplace</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.Module.Synchronize" xml:space="preserve">
|
||||||
|
<value>Error Retrieving Module Information From The Marketplace</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -121,7 +121,7 @@
|
|||||||
<value>Export</value>
|
<value>Export</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Content.HelpText" xml:space="preserve">
|
<data name="Content.HelpText" xml:space="preserve">
|
||||||
<value>The Exported Module Content</value>
|
<value>Select the Export option and you will be able to view the module content</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Content.Text" xml:space="preserve">
|
<data name="Content.Text" xml:space="preserve">
|
||||||
<value>Content: </value>
|
<value>Content: </value>
|
||||||
@ -135,4 +135,25 @@
|
|||||||
<data name="Export Content" xml:space="preserve">
|
<data name="Export Content" xml:space="preserve">
|
||||||
<value>Export Content</value>
|
<value>Export Content</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Content.Heading" xml:space="preserve">
|
||||||
|
<value>Content</value>
|
||||||
|
</data>
|
||||||
|
<data name="File.Heading" xml:space="preserve">
|
||||||
|
<value>File</value>
|
||||||
|
</data>
|
||||||
|
<data name="Folder.Text" xml:space="preserve">
|
||||||
|
<value>Folder:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Folder.HelpText" xml:space="preserve">
|
||||||
|
<value>Select a folder where you wish to save the exported content</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Content.Export" xml:space="preserve">
|
||||||
|
<value>Please Select A Folder And Provide A Filename Before Choosing Export</value>
|
||||||
|
</data>
|
||||||
|
<data name="Filename.Text" xml:space="preserve">
|
||||||
|
<value>Filename:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Filename.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify a name for the file (without an extension)</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -189,4 +189,19 @@
|
|||||||
<data name="ModuleSettings.Title" xml:space="preserve">
|
<data name="ModuleSettings.Title" xml:space="preserve">
|
||||||
<value>Module Settings</value>
|
<value>Module Settings</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Header.Text" xml:space="preserve">
|
||||||
|
<value>Header:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Header.HelpText" xml:space="preserve">
|
||||||
|
<value>Optionally provide content to be injected above the module instance</value>
|
||||||
|
</data>
|
||||||
|
<data name="Footer.Text" xml:space="preserve">
|
||||||
|
<value>Footer:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Footer.HelpText" xml:space="preserve">
|
||||||
|
<value>Optionally provide content to be injected below the module instance</value>
|
||||||
|
</data>
|
||||||
|
<data name="ModuleContent.Heading" xml:space="preserve">
|
||||||
|
<value>Content</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -169,7 +169,7 @@
|
|||||||
<value>Select whether the page is part of the site navigation or hidden</value>
|
<value>Select whether the page is part of the site navigation or hidden</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UrlPath.HelpText" xml:space="preserve">
|
<data name="UrlPath.HelpText" xml:space="preserve">
|
||||||
<value>Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. If the page is intended to be the root path specify '/'.</value>
|
<value>Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. Please note that spaces and punctuation will be replaced by a dash. If the page is intended to be the root path specify '/'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Redirect.HelpText" xml:space="preserve">
|
<data name="Redirect.HelpText" xml:space="preserve">
|
||||||
<value>Optionally enter a url which this page should redirect to when a user navigates to it</value>
|
<value>Optionally enter a url which this page should redirect to when a user navigates to it</value>
|
||||||
@ -297,4 +297,16 @@
|
|||||||
<data name="ExpiryDate.Text" xml:space="preserve">
|
<data name="ExpiryDate.Text" xml:space="preserve">
|
||||||
<value>Expiry Date: </value>
|
<value>Expiry Date: </value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PersonalizedUrlPath.Text" xml:space="preserve">
|
||||||
|
<value>Url Path:</value>
|
||||||
|
</data>
|
||||||
|
<data name="PersonalizedUrlPath.HelpText" xml:space="preserve">
|
||||||
|
<value>Provide a url path for your personalized page. Please note that spaces and punctuation will be replaced by a dash.</value>
|
||||||
|
</data>
|
||||||
|
<data name="UpdateModulePermissions.Text" xml:space="preserve">
|
||||||
|
<value>Update Module Permissions?</value>
|
||||||
|
</data>
|
||||||
|
<data name="UpdateModulePermissions.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if changes made to page permissions should be propagated to the modules on this page</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -195,4 +195,25 @@
|
|||||||
<data name="Modules.Heading" xml:space="preserve">
|
<data name="Modules.Heading" xml:space="preserve">
|
||||||
<value>Modules</value>
|
<value>Modules</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Message.Page.Restore" xml:space="preserve">
|
||||||
|
<value>You Cannot Restore A Page If Its Parent Is Deleted</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Page.Restore" xml:space="preserve">
|
||||||
|
<value>Page Restored Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Page.Delete" xml:space="preserve">
|
||||||
|
<value>Page Deleted Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Pages.Deleted" xml:space="preserve">
|
||||||
|
<value>All Pages Deleted Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Module.Restore" xml:space="preserve">
|
||||||
|
<value>Module Restored Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Module.Delete" xml:space="preserve">
|
||||||
|
<value>Module Deleted Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Modules.Delete" xml:space="preserve">
|
||||||
|
<value>All Modules Deleted Successfully</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -180,4 +180,10 @@
|
|||||||
<data name="Login" xml:space="preserve">
|
<data name="Login" xml:space="preserve">
|
||||||
<value>Already have account? Login now.</value>
|
<value>Already have account? Login now.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TimeZone.Text" xml:space="preserve">
|
||||||
|
<value>Time Zone:</value>
|
||||||
|
</data>
|
||||||
|
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||||
|
<value>Your time zone</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -139,7 +139,7 @@
|
|||||||
<value>Ignore Entities: </value>
|
<value>Ignore Entities: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IgnoreEntities.HelpText" xml:space="preserve">
|
<data name="IgnoreEntities.HelpText" xml:space="preserve">
|
||||||
<value>Comma delimited list of entities which should be ignored</value>
|
<value>Comma delimited list of entities which should be ignored. By default File entities are ignored.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MinimumWordLength.Text" xml:space="preserve">
|
<data name="MinimumWordLength.Text" xml:space="preserve">
|
||||||
<value>Word Length: </value>
|
<value>Word Length: </value>
|
||||||
@ -154,7 +154,7 @@
|
|||||||
<value>Comma delimited list of words which should be ignored</value>
|
<value>Comma delimited list of words which should be ignored</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Save" xml:space="preserve">
|
<data name="Success.Save" xml:space="preserve">
|
||||||
<value>Search Settings Saved Successfully</value>
|
<value>Search Settings Saved Successfully. You Will Need Reindex For Your Changes To Be Reflected In The Search Results.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Save" xml:space="preserve">
|
<data name="Error.Save" xml:space="preserve">
|
||||||
<value>Error Saving Search Settings</value>
|
<value>Error Saving Search Settings</value>
|
||||||
|
@ -118,7 +118,7 @@
|
|||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="NoCriteria" xml:space="preserve">
|
<data name="NoCriteria" xml:space="preserve">
|
||||||
<value>You Must Provide Some Search Criteria</value>
|
<value>Please Enter Some Search Criteria</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NoResult" xml:space="preserve">
|
<data name="NoResult" xml:space="preserve">
|
||||||
<value>No Content Matches The Criteria Provided</value>
|
<value>No Content Matches The Criteria Provided</value>
|
||||||
|
@ -349,7 +349,7 @@
|
|||||||
<value>Relay Configured?</value>
|
<value>Relay Configured?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SiteMap.HelpText" xml:space="preserve">
|
<data name="SiteMap.HelpText" xml:space="preserve">
|
||||||
<value>The site map url for this site which can be submitted to search engines for indexing</value>
|
<value>The site map url for this site which can be submitted to search engines for indexing. The sitemap is cached for 5 minutes and the cache can be manually cleared.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SiteMap.Text" xml:space="preserve">
|
<data name="SiteMap.Text" xml:space="preserve">
|
||||||
<value>Site Map:</value>
|
<value>Site Map:</value>
|
||||||
@ -402,18 +402,6 @@
|
|||||||
<data name="Retention.Text" xml:space="preserve">
|
<data name="Retention.Text" xml:space="preserve">
|
||||||
<value>Retention (Days):</value>
|
<value>Retention (Days):</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ImageExtensions.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter a comma separated list of image file extensions</value>
|
|
||||||
</data>
|
|
||||||
<data name="ImageExtensions.Text" xml:space="preserve">
|
|
||||||
<value>Image Extensions:</value>
|
|
||||||
</data>
|
|
||||||
<data name="UploadableFileExtensions.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter a comma separated list of uploadable file extensions</value>
|
|
||||||
</data>
|
|
||||||
<data name="UploadableFileExtensions.Text" xml:space="preserve">
|
|
||||||
<value>Uploadable File Extensions:</value>
|
|
||||||
</data>
|
|
||||||
<data name="HybridEnabled.HelpText" xml:space="preserve">
|
<data name="HybridEnabled.HelpText" xml:space="preserve">
|
||||||
<value>Specifies if the site can be integrated with an external .NET MAUI hybrid application</value>
|
<value>Specifies if the site can be integrated with an external .NET MAUI hybrid application</value>
|
||||||
</data>
|
</data>
|
||||||
@ -435,4 +423,34 @@
|
|||||||
<data name="Functionality" xml:space="preserve">
|
<data name="Functionality" xml:space="preserve">
|
||||||
<value>Functionality</value>
|
<value>Functionality</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="System" xml:space="preserve">
|
||||||
|
<value>System</value>
|
||||||
|
</data>
|
||||||
|
<data name="CookieConsent.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if cookie consent is enabled on this site. Please note this option must be used in conjunction with a Theme which supports cookie consent.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CookieConsent.Text" xml:space="preserve">
|
||||||
|
<value>Cookie Consent:</value>
|
||||||
|
</data>
|
||||||
|
<data name="OptIn" xml:space="preserve">
|
||||||
|
<value>Opt-In (GDPR)</value>
|
||||||
|
</data>
|
||||||
|
<data name="OptOut" xml:space="preserve">
|
||||||
|
<value>Opt-Out (CCPA)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Theme.Heading" xml:space="preserve">
|
||||||
|
<value>Theme</value>
|
||||||
|
</data>
|
||||||
|
<data name="SiteMap.EvictCache" xml:space="preserve">
|
||||||
|
<value>Clear Cache</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.SiteMap.CacheEvicted" xml:space="preserve">
|
||||||
|
<value>Site Map Cache Cleared</value>
|
||||||
|
</data>
|
||||||
|
<data name="TimeZone.Text" xml:space="preserve">
|
||||||
|
<value>Time Zone:</value>
|
||||||
|
</data>
|
||||||
|
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||||
|
<value>The default time zone for the site</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -117,8 +117,8 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="Access.ApiFramework" xml:space="preserve">
|
<data name="Swagger" xml:space="preserve">
|
||||||
<value>Access Swagger API</value>
|
<value>Swagger UI</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FrameworkVersion.HelpText" xml:space="preserve">
|
<data name="FrameworkVersion.HelpText" xml:space="preserve">
|
||||||
<value>Framework Version</value>
|
<value>Framework Version</value>
|
||||||
@ -220,10 +220,10 @@
|
|||||||
<value>You Have Been Successfully Registered For Updates</value>
|
<value>You Have Been Successfully Registered For Updates</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PackageManager.HelpText" xml:space="preserve">
|
<data name="PackageManager.HelpText" xml:space="preserve">
|
||||||
<value>Specify The Package Manager Service For Installing Modules, Themes, And Translations. If This Field Is Blank It Means The Package Manager Service Is Disabled For This Installation.</value>
|
<value>Specify The Url Of The Package Manager Service For Installing Modules, Themes, And Translations. If This Field Is Blank It Means The Package Manager Service Is Disabled For This Installation.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PackageManager.Text" xml:space="preserve">
|
<data name="PackageManager.Text" xml:space="preserve">
|
||||||
<value>Package Manager:</value>
|
<value>Package Manager Url:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Swagger.HelpText" xml:space="preserve">
|
<data name="Swagger.HelpText" xml:space="preserve">
|
||||||
<value>Specify If Swagger Is Enabled For Your Server API</value>
|
<value>Specify If Swagger Is Enabled For Your Server API</value>
|
||||||
@ -294,4 +294,19 @@
|
|||||||
<data name="Process.Text" xml:space="preserve">
|
<data name="Process.Text" xml:space="preserve">
|
||||||
<value>Process: </value>
|
<value>Process: </value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PackageManagerEmail.Text" xml:space="preserve">
|
||||||
|
<value>Package Manager Email:</value>
|
||||||
|
</data>
|
||||||
|
<data name="PackageManagerEmail.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify The Email Address Of The User Account Used For Interacting With The Package Manager Service. This Account Is Used For Managing Packages Across Multiple Installations.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CacheControl.Text" xml:space="preserve">
|
||||||
|
<value>Static Asset Caching:</value>
|
||||||
|
</data>
|
||||||
|
<data name="CacheControl.HelpText" xml:space="preserve">
|
||||||
|
<value>Provide a Cache-Control directive for static assets. For example 'public, max-age=60' indicates that static assets should be cached for 60 seconds. A blank value indicates caching is not enabled.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Endpoints" xml:space="preserve">
|
||||||
|
<value>API Endpoints</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -132,8 +132,8 @@
|
|||||||
<data name="Owner.Text" xml:space="preserve">
|
<data name="Owner.Text" xml:space="preserve">
|
||||||
<value>Owner: </value>
|
<value>Owner: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ReferenceUrl.Text" xml:space="preserve">
|
<data name="Url.Text" xml:space="preserve">
|
||||||
<value>Reference Url: </value>
|
<value>Url: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Contact.Text" xml:space="preserve">
|
<data name="Contact.Text" xml:space="preserve">
|
||||||
<value>Contact: </value>
|
<value>Contact: </value>
|
||||||
@ -153,8 +153,8 @@
|
|||||||
<data name="Owner.HelpText" xml:space="preserve">
|
<data name="Owner.HelpText" xml:space="preserve">
|
||||||
<value>The owner or creator of the theme</value>
|
<value>The owner or creator of the theme</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ReferenceUrl.HelpText" xml:space="preserve">
|
<data name="Url.HelpText" xml:space="preserve">
|
||||||
<value>The reference url of the theme</value>
|
<value>The url of the theme</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Contact.HelpText" xml:space="preserve">
|
<data name="Contact.HelpText" xml:space="preserve">
|
||||||
<value>The contact for the theme</value>
|
<value>The contact for the theme</value>
|
||||||
@ -180,16 +180,4 @@
|
|||||||
<data name="View License" xml:space="preserve">
|
<data name="View License" xml:space="preserve">
|
||||||
<value>View License</value>
|
<value>View License</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Validate" xml:space="preserve">
|
|
||||||
<value>Error Validating Package</value>
|
|
||||||
</data>
|
|
||||||
<data name="Message.Download" xml:space="preserve">
|
|
||||||
<value>Package Version Has Been Verified. Please Select The Download Button To Obtain The Package.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Message.Validate" xml:space="preserve">
|
|
||||||
<value>This Package Version Has Not Been Registered In The Oqtane Marketplace Or You Do Not Have The Right To Use It From This Installation</value>
|
|
||||||
</data>
|
|
||||||
<data name="Validate" xml:space="preserve">
|
|
||||||
<value>Validate</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
</root>
|
@ -156,4 +156,16 @@
|
|||||||
<data name="Enabled" xml:space="preserve">
|
<data name="Enabled" xml:space="preserve">
|
||||||
<value>Enabled?</value>
|
<value>Enabled?</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Assign" xml:space="preserve">
|
||||||
|
<value>Assign</value>
|
||||||
|
</data>
|
||||||
|
<data name="Synchronize" xml:space="preserve">
|
||||||
|
<value>Check For Updates</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Theme.Synchronize" xml:space="preserve">
|
||||||
|
<value>Theme Information Has Been Retrieved From The Marketplace</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.Theme.Synchronize" xml:space="preserve">
|
||||||
|
<value>Error Retrieving Theme Information From The Marketplace</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -124,7 +124,7 @@
|
|||||||
<value>Error Downloading Framework Package</value>
|
<value>Error Downloading Framework Package</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Framework.HelpText" xml:space="preserve">
|
<data name="Framework.HelpText" xml:space="preserve">
|
||||||
<value>Upload a framework package and select Install to complete the installation</value>
|
<value>Upload A Framework Package (Oqtane.Framework.#.#.#.nupkg) And Then Select Upgrade</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Framework.Text" xml:space="preserve">
|
<data name="Framework.Text" xml:space="preserve">
|
||||||
<value>Framework: </value>
|
<value>Framework: </value>
|
||||||
@ -144,13 +144,16 @@
|
|||||||
<data name="Message.Text" xml:space="preserve">
|
<data name="Message.Text" xml:space="preserve">
|
||||||
<value>Framework Is Already Up To Date</value>
|
<value>Framework Is Already Up To Date</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MessageUpgrade.Text" xml:space="preserve">
|
|
||||||
<value>Upload A Framework Package (Oqtane.Framework.version.nupkg) And Then Select Upgrade</value>
|
|
||||||
</data>
|
|
||||||
<data name="Localhost.Text" xml:space="preserve">
|
<data name="Localhost.Text" xml:space="preserve">
|
||||||
<value>You Cannot Perform A System Update In A Development Environment</value>
|
<value>You Cannot Perform A System Update In A Development Environment</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Disclaimer.Text" xml:space="preserve">
|
<data name="Disclaimer.Text" xml:space="preserve">
|
||||||
<value>Please Note That The System Update Capability Is A Simplified Upgrade Process Intended For Small To Medium Sized Installations. For Larger Enterprise Installations You Will Want To Use A Manual Upgrade Process. Also Note That The System Update Capability Is Not Recommended When Using Microsoft Azure Due To The Limitations Of That Environment. </value>
|
<value>Please Note That The System Update Capability Is A Simplified Upgrade Process Intended For Small To Medium Sized Installations. For Larger Enterprise Installations You Will Want To Use A Manual Upgrade Process.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Backup.Text" xml:space="preserve">
|
||||||
|
<value>Backup Files?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Backup.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if you want to backup files during the upgrade process. Disabling this option will reduce the time required for the upgrade.</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -121,10 +121,10 @@
|
|||||||
<value>Redirect To:</value>
|
<value>Redirect To:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MappedUrl.HelpText" xml:space="preserve">
|
<data name="MappedUrl.HelpText" xml:space="preserve">
|
||||||
<value>A relative or absolute Url where the user will be redirected</value>
|
<value>A Url where the user will be redirected (absolute or relative). Use '/' for site root path.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Url.HelpText" xml:space="preserve">
|
<data name="Url.HelpText" xml:space="preserve">
|
||||||
<value>An absolute Url identifying a path to a specific page in the site</value>
|
<value>A Url identifying a path to a specific page in the site (absolute or relative)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Url.Text" xml:space="preserve">
|
<data name="Url.Text" xml:space="preserve">
|
||||||
<value>Url:</value>
|
<value>Url:</value>
|
||||||
@ -141,4 +141,7 @@
|
|||||||
<data name="Message.SaveUrlMapping" xml:space="preserve">
|
<data name="Message.SaveUrlMapping" xml:space="preserve">
|
||||||
<value>The Url must belong to the current site</value>
|
<value>The Url must belong to the current site</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Generate" xml:space="preserve">
|
||||||
|
<value>Generate</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -121,10 +121,10 @@
|
|||||||
<value>Redirect To:</value>
|
<value>Redirect To:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MappedUrl.HelpText" xml:space="preserve">
|
<data name="MappedUrl.HelpText" xml:space="preserve">
|
||||||
<value>A relative or absolute Url where the user will be redirected</value>
|
<value>A Url where the user will be redirected (absolute or relative). Use '/' for site root path.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Url.HelpText" xml:space="preserve">
|
<data name="Url.HelpText" xml:space="preserve">
|
||||||
<value>A relative Url identifying a path to a specific page in the site</value>
|
<value>A Url identifying a path to a specific page in the site (absolute or relative)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Url.Text" xml:space="preserve">
|
<data name="Url.Text" xml:space="preserve">
|
||||||
<value>Url:</value>
|
<value>Url:</value>
|
||||||
|
@ -162,4 +162,10 @@
|
|||||||
<data name="Edit.Text" xml:space="preserve">
|
<data name="Edit.Text" xml:space="preserve">
|
||||||
<value>Edit</value>
|
<value>Edit</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Retention.Text" xml:space="preserve">
|
||||||
|
<value>Retention (Days):</value>
|
||||||
|
</data>
|
||||||
|
<data name="Retention.HelpText" xml:space="preserve">
|
||||||
|
<value>Number of days of broken urls to retain</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -246,4 +246,10 @@
|
|||||||
<data name="Logout Everywhere" xml:space="preserve">
|
<data name="Logout Everywhere" xml:space="preserve">
|
||||||
<value>Logout Everywhere</value>
|
<value>Logout Everywhere</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TimeZone.Text" xml:space="preserve">
|
||||||
|
<value>Time Zone:</value>
|
||||||
|
</data>
|
||||||
|
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||||
|
<value>Your time zone</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -156,4 +156,10 @@
|
|||||||
<data name="Notify.Text" xml:space="preserve">
|
<data name="Notify.Text" xml:space="preserve">
|
||||||
<value>Notify?</value>
|
<value>Notify?</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TimeZone.Text" xml:space="preserve">
|
||||||
|
<value>Time Zone:</value>
|
||||||
|
</data>
|
||||||
|
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||||
|
<value>The user's time zone</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -195,4 +195,31 @@
|
|||||||
<data name="LastLogin.Text" xml:space="preserve">
|
<data name="LastLogin.Text" xml:space="preserve">
|
||||||
<value>Last Login:</value>
|
<value>Last Login:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DeleteUser.Header" xml:space="preserve">
|
||||||
|
<value>Delete User</value>
|
||||||
|
</data>
|
||||||
|
<data name="DeleteUser.Text" xml:space="preserve">
|
||||||
|
<value>Delete</value>
|
||||||
|
</data>
|
||||||
|
<data name="DeleteUser.Message" xml:space="preserve">
|
||||||
|
<value>Are You Sure You Wish To Permanently Delete This User?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Impersonate" xml:space="preserve">
|
||||||
|
<value>Impersonate</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.User.Impersonate" xml:space="preserve">
|
||||||
|
<value>Unable To Impersonate User</value>
|
||||||
|
</data>
|
||||||
|
<data name="TimeZone.Text" xml:space="preserve">
|
||||||
|
<value>Time Zone:</value>
|
||||||
|
</data>
|
||||||
|
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||||
|
<value>The user's time zone</value>
|
||||||
|
</data>
|
||||||
|
<data name="Confirmed.Text" xml:space="preserve">
|
||||||
|
<value>Confirmed?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Confirmed.HelpText" xml:space="preserve">
|
||||||
|
<value>Indicates if the user's email is verified</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -132,6 +132,18 @@
|
|||||||
<data name="AllowRegistration.Text" xml:space="preserve">
|
<data name="AllowRegistration.Text" xml:space="preserve">
|
||||||
<value>Allow Registration? </value>
|
<value>Allow Registration? </value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="RegisterUrl.HelpText" xml:space="preserve">
|
||||||
|
<value>Optionally provide a custom registration url</value>
|
||||||
|
</data>
|
||||||
|
<data name="RegisterUrl.Text" xml:space="preserve">
|
||||||
|
<value>Register Url: </value>
|
||||||
|
</data>
|
||||||
|
<data name="ProfileUrl.HelpText" xml:space="preserve">
|
||||||
|
<value>Optionally provide a custom user profile url</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProfileUrl.Text" xml:space="preserve">
|
||||||
|
<value>Profile Url: </value>
|
||||||
|
</data>
|
||||||
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||||
<value>Error Saving Settings</value>
|
<value>Error Saving Settings</value>
|
||||||
</data>
|
</data>
|
||||||
@ -208,7 +220,7 @@
|
|||||||
<value>Do you want to allow users to sign in using a username and password that is managed locally on this site? Note that you should only disable this option if you have already sucessfully configured an external login provider, or else you may lock yourself out of the site.</value>
|
<value>Do you want to allow users to sign in using a username and password that is managed locally on this site? Note that you should only disable this option if you have already sucessfully configured an external login provider, or else you may lock yourself out of the site.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AllowSiteLogin.Text" xml:space="preserve">
|
<data name="AllowSiteLogin.Text" xml:space="preserve">
|
||||||
<value>Allow Login?</value>
|
<value>Allow Local Login?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Authority.HelpText" xml:space="preserve">
|
<data name="Authority.HelpText" xml:space="preserve">
|
||||||
<value>The authority url or issuer url associated with the identity provider</value>
|
<value>The authority url or issuer url associated with the identity provider</value>
|
||||||
@ -495,4 +507,28 @@
|
|||||||
<data name="OIDC" xml:space="preserve">
|
<data name="OIDC" xml:space="preserve">
|
||||||
<value>OpenID Connect (OIDC)</value>
|
<value>OpenID Connect (OIDC)</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SaveTokens.Text" xml:space="preserve">
|
||||||
|
<value>Save Tokens?</value>
|
||||||
|
</data>
|
||||||
|
<data name="SaveTokens.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify whether access and refresh tokens should be saved after a successful login. The default is false to reduce the size of the authentication cookie.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.DeleteUser" xml:space="preserve">
|
||||||
|
<value>User Deleted Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.DeleteUser" xml:space="preserve">
|
||||||
|
<value>Error Deleting User</value>
|
||||||
|
</data>
|
||||||
|
<data name="LogoutEverywhere.Text" xml:space="preserve">
|
||||||
|
<value>Logout Everywhere?</value>
|
||||||
|
</data>
|
||||||
|
<data name="LogoutEverywhere.HelpText" xml:space="preserve">
|
||||||
|
<value>Do you want users to be logged out of every active session on any device, or only their current session?</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowHostRole.Text" xml:space="preserve">
|
||||||
|
<value>Allow Host Role?</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowHostRole.HelpText" xml:space="preserve">
|
||||||
|
<value>Indicate if host roles are supported from the identity provider. Please use caution with this option as it allows the host user to administrate every site within your installation.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -198,4 +198,13 @@
|
|||||||
<data name="Duration.Text" xml:space="preserve">
|
<data name="Duration.Text" xml:space="preserve">
|
||||||
<value>Session Duration:</value>
|
<value>Session Duration:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Robots.Heading" xml:space="preserve">
|
||||||
|
<value>Robots.txt</value>
|
||||||
|
</data>
|
||||||
|
<data name="Robots.Text" xml:space="preserve">
|
||||||
|
<value>Instructions:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Robots.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify your robots.txt instructions to provide bots with guidance on which parts of your site should be indexed</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -127,7 +127,7 @@
|
|||||||
<value>Error Loading Files</value>
|
<value>Error Loading Files</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.File.Upload" xml:space="preserve">
|
<data name="Error.File.Upload" xml:space="preserve">
|
||||||
<value>File Upload Failed Or Is Still In Progress</value>
|
<value>File Upload Failed</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.File.NotSelected" xml:space="preserve">
|
<data name="Message.File.NotSelected" xml:space="preserve">
|
||||||
<value>You Have Not Selected A File To Upload</value>
|
<value>You Have Not Selected A File To Upload</value>
|
||||||
|
126
Oqtane.Client/Resources/Modules/HtmlText/Settings.resx
Normal file
126
Oqtane.Client/Resources/Modules/HtmlText/Settings.resx
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="DynamicTokens.HelpText" xml:space="preserve">
|
||||||
|
<value>Do you wish to allow tokens to be dynamically replaced? Please note that this will affect the performance of your site.</value>
|
||||||
|
</data>
|
||||||
|
<data name="DynamicTokens.Text" xml:space="preserve">
|
||||||
|
<value>Dynamic Tokens?</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
@ -427,7 +427,7 @@
|
|||||||
<value>At Least One Uppercase Letter</value>
|
<value>At Least One Uppercase Letter</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Password.ValidationCriteria" xml:space="preserve">
|
<data name="Password.ValidationCriteria" xml:space="preserve">
|
||||||
<value>Passwords Must Have A Minimum Length Of {0} Characters, Including At Least {1} Unique Character(s), {2}{3}{4}{5} To Satisfy Password Compexity Requirements For This Site.</value>
|
<value>Passwords Must Have A Minimum Length Of {0} Characters, Including At Least {1} Unique Character(s), {2}{3}{4}{5} To Satisfy Password Complexity Requirements For This Site.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ProfileInvalid" xml:space="preserve">
|
<data name="ProfileInvalid" xml:space="preserve">
|
||||||
<value>{0} Is Not Valid</value>
|
<value>{0} Is Not Valid</value>
|
||||||
@ -474,4 +474,7 @@
|
|||||||
<data name="User" xml:space="preserve">
|
<data name="User" xml:space="preserve">
|
||||||
<value>User</value>
|
<value>User</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Path" xml:space="preserve">
|
||||||
|
<value>Path</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
129
Oqtane.Client/Resources/Themes/Controls/CookieConsent.resx
Normal file
129
Oqtane.Client/Resources/Themes/Controls/CookieConsent.resx
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Confirm" xml:space="preserve">
|
||||||
|
<value>Confirm</value>
|
||||||
|
</data>
|
||||||
|
<data name="ConsentNotice" xml:space="preserve">
|
||||||
|
<value>I agree to use cookies to provide the best possible user experience for this site. I understand that I can change these preferences at any time.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Privacy" xml:space="preserve">
|
||||||
|
<value>Privacy</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
|
47
Oqtane.Client/Services/CookieConsentService.cs
Normal file
47
Oqtane.Client/Services/CookieConsentService.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using Oqtane.Models;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System;
|
||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Oqtane.Services
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="ICookieConsentService" />
|
||||||
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
|
public class CookieConsentService : ServiceBase, ICookieConsentService
|
||||||
|
{
|
||||||
|
public CookieConsentService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
||||||
|
|
||||||
|
private string ApiUrl => CreateApiUrl("CookieConsent");
|
||||||
|
|
||||||
|
public async Task<bool> IsActionedAsync()
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<bool>($"{ApiUrl}/IsActioned");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> CanTrackAsync(bool optOut)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<bool>($"{ApiUrl}/CanTrack?optout=" + optOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> CreateActionedCookieAsync()
|
||||||
|
{
|
||||||
|
var cookie = await GetStringAsync($"{ApiUrl}/CreateActionedCookie");
|
||||||
|
return cookie ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> CreateConsentCookieAsync()
|
||||||
|
{
|
||||||
|
var cookie = await GetStringAsync($"{ApiUrl}/CreateConsentCookie");
|
||||||
|
return cookie ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> WithdrawConsentCookieAsync()
|
||||||
|
{
|
||||||
|
var cookie = await GetStringAsync($"{ApiUrl}/WithdrawConsentCookie");
|
||||||
|
return cookie ?? string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -42,14 +42,6 @@ namespace Oqtane.Services
|
|||||||
return await PutJsonAsync<Folder>($"{ApiUrl}/{folder.FolderId}", folder);
|
return await PutJsonAsync<Folder>($"{ApiUrl}/{folder.FolderId}", folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateFolderOrderAsync(int siteId, int folderId, int? parentId)
|
|
||||||
{
|
|
||||||
var parent = parentId == null
|
|
||||||
? string.Empty
|
|
||||||
: parentId.ToString();
|
|
||||||
await PutAsync($"{ApiUrl}/?siteid={siteId}&folderid={folderId}&parentid={parent}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteFolderAsync(int folderId)
|
public async Task DeleteFolderAsync(int folderId)
|
||||||
{
|
{
|
||||||
await DeleteAsync($"{ApiUrl}/{folderId}");
|
await DeleteAsync($"{ApiUrl}/{folderId}");
|
||||||
|
@ -47,19 +47,14 @@ namespace Oqtane.Services
|
|||||||
return await PostJsonAsync<InstallConfig,Installation>(ApiUrl, config);
|
return await PostJsonAsync<InstallConfig,Installation>(ApiUrl, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Installation> Upgrade()
|
public async Task<Installation> Upgrade(bool backup)
|
||||||
{
|
{
|
||||||
return await GetJsonAsync<Installation>($"{ApiUrl}/upgrade");
|
return await GetJsonAsync<Installation>($"{ApiUrl}/upgrade/?backup={backup}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RestartAsync()
|
public async Task RestartAsync()
|
||||||
{
|
{
|
||||||
await PostAsync($"{ApiUrl}/restart");
|
await PostAsync($"{ApiUrl}/restart");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RegisterAsync(string email)
|
|
||||||
{
|
|
||||||
await PostJsonAsync($"{ApiUrl}/register?email={WebUtility.UrlEncode(email)}", true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
Oqtane.Client/Services/Interfaces/ICookieConsentService.cs
Normal file
42
Oqtane.Client/Services/Interfaces/ICookieConsentService.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using Oqtane.Models;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Oqtane.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Service to retrieve cookie consent information.
|
||||||
|
/// </summary>
|
||||||
|
public interface ICookieConsentService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get cookie consent bar actioned status
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<bool> IsActionedAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get cookie consent status
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<bool> CanTrackAsync(bool optOut);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// create actioned cookie
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<string> CreateActionedCookieAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// create consent cookie
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<string> CreateConsentCookieAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// widhdraw consent cookie
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<string> WithdrawConsentCookieAsync();
|
||||||
|
}
|
||||||
|
}
|
@ -39,15 +39,6 @@ namespace Oqtane.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Folder> UpdateFolderAsync(Folder folder);
|
Task<Folder> UpdateFolderAsync(Folder folder);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update the internal Folder-Order within the list of Folders.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="siteId">Reference to the <see cref="Site"/></param>
|
|
||||||
/// <param name="folderId">Reference to a <see cref="Folder"/> for the security check</param>
|
|
||||||
/// <param name="parentId">Reference to the Parent <see cref="Folder"/> or null - this Folders children will be re-sorted.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task UpdateFolderOrderAsync(int siteId, int folderId, int? parentId);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a <see cref="Folder"/>
|
/// Delete a <see cref="Folder"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user