Compare commits
807 Commits
Author | SHA1 | Date | |
---|---|---|---|
8b80f72313 | |||
06ebce31ca | |||
59db8ba997 | |||
df37d4aa7f | |||
fd9935c800 | |||
c057430488 | |||
767fa78e22 | |||
a0e289dcd6 | |||
c62d147254 | |||
f739bee353 | |||
db4dfb69fb | |||
9729a5ef16 | |||
6f12818352 | |||
75fc318da0 | |||
acf71cc2c2 | |||
42efe10473 | |||
b77e72880b | |||
297c1524b4 | |||
6140743769 | |||
d5ca700828 | |||
a7e1fe76c3 | |||
f6c55279d1 | |||
826f4835bb | |||
119a28def1 | |||
c1ffb8bc33 | |||
60cc9d14af | |||
7cf4f8fdaa | |||
1b84e83061 | |||
b0d2ee8760 | |||
2022432d35 | |||
c0ed335d84 | |||
4964562866 | |||
f78dc443ad | |||
56b47db778 | |||
2d4bf17b28 | |||
3b1819c68d | |||
575bbdb53b | |||
2fa7482028 | |||
e5062317e2 | |||
543f4fa3c2 | |||
49cdf69815 | |||
04196a1a19 | |||
b8622b8708 | |||
a2feca0ba3 | |||
ae6c6a75b2 | |||
bd987e9531 | |||
24d69fd820 | |||
9e2fa8d7f1 | |||
74ba2f7283 | |||
7603b5c63f | |||
03566afe66 | |||
3c2e314e2d | |||
1fcf08b5cd | |||
c13db89ed4 | |||
e68ae9e8a6 | |||
fb252d6db3 | |||
df959353d6 | |||
fbc443483d | |||
00f1dbc3dd | |||
c6021ff012 | |||
7a8cfcee35 | |||
c15586a1c4 | |||
be1d124e78 | |||
6fabf84d05 | |||
3299275da2 | |||
5539243bf3 | |||
c3d330f500 | |||
8c9e886136 | |||
cfde9944f8 | |||
b35d778abe | |||
1e9ee81df3 | |||
545d5730b6 | |||
28e645f9ca | |||
5b5c8a4beb | |||
6178be974a | |||
7771c3159b | |||
fc1e9c5d71 | |||
359de5b85e | |||
68dc4904cf | |||
057fd02e26 | |||
5c86ef6682 | |||
7c14bd799f | |||
edac046fcd | |||
8b23b386f7 | |||
e9bed59032 | |||
54077be32c | |||
30ad442dd1 | |||
b0c677d5a7 | |||
abe1b93e3c | |||
fd699cbb73 | |||
6f93ca11de | |||
916663b493 | |||
dbf2cddd87 | |||
d3c248cf5c | |||
bd93a94bb7 | |||
a46836e2a6 | |||
a1d88b4faa | |||
29741c0ec8 | |||
0b5fb92452 | |||
65782e87c1 | |||
6403df3330 | |||
c6a8f5305a | |||
d354e63267 | |||
836b174d15 | |||
4435f25ee6 | |||
4ab4bf4a3a | |||
d2f1d3c86c | |||
98257de005 | |||
5ea5c6ff7d | |||
441324d354 | |||
44f093b2fa | |||
38a16d1ae2 | |||
6b9de40442 | |||
d9c9eb9799 | |||
e88c8eee0f | |||
a6ca843ced | |||
6967a5cc14 | |||
e0ebf70907 | |||
53d0202f3b | |||
8daf38654d | |||
17337440f2 | |||
8e5e79a799 | |||
5c1cf14303 | |||
f2ad796104 | |||
886df69058 | |||
703aa95e60 | |||
7919e14d90 | |||
c8ef191660 | |||
840b656d1c | |||
d28516b6b1 | |||
5797bf549c | |||
e1ea721ea9 | |||
5ed1284baf | |||
e507023a03 | |||
2b328b9bb2 | |||
d155e13399 | |||
6993d4782d | |||
9267efce01 | |||
8c88cec863 | |||
b4b9976567 | |||
3cbd820d9c | |||
edd77b0222 | |||
c0991df9a2 | |||
26921c899e | |||
a1e5912d37 | |||
037f1ec887 | |||
89ab44590b | |||
4a20be8b34 | |||
32a401ba67 | |||
138c01aef8 | |||
3e54bc9c77 | |||
9966fc4651 | |||
c9ed5ec98f | |||
1f4ae5dbfb | |||
d0d3cc8faa | |||
7513ae28f0 | |||
c151c6f55a | |||
d491aeeba6 | |||
ab93d0acea | |||
f40f3f934f | |||
4d57adb393 | |||
e91db18677 | |||
9a88d65ff7 | |||
211d8c7f19 | |||
763cdca114 | |||
0d56d35646 | |||
d1e80cb86a | |||
2e116489c8 | |||
a94daa1216 | |||
ad57d665cc | |||
db2c42f0f4 | |||
b713cf86c7 | |||
11d02ccf44 | |||
54f3c8beac | |||
2ed51bf1f3 | |||
9f859f024c | |||
d47175df8a | |||
d6a80d36b1 | |||
a857e3f31e | |||
918dfb05cd | |||
f22e0c4384 | |||
daa08626ae | |||
45592e6acd | |||
6944eb3392 | |||
85f20aca58 | |||
ca8d8b3587 | |||
74921a0686 | |||
be4296f288 | |||
836de56276 | |||
ef60ac3836 | |||
bdd1ba05e8 | |||
f0a22d5517 | |||
417c8d7874 | |||
5a111cdb2a | |||
ef2f779f71 | |||
f0fd0db7bb | |||
b4ab45d2e7 | |||
73c4bcee30 | |||
d4daf098e1 | |||
95de1fff69 | |||
96480b4382 | |||
14ae553557 | |||
4de809e275 | |||
a383382529 | |||
d2b3061ed9 | |||
073b10929a | |||
6a2cfcab34 | |||
00c85ae7d3 | |||
d1b1e88389 | |||
5679ff5df9 | |||
3f28b39da0 | |||
ee21536742 | |||
6fafeedeb9 | |||
d86c53858e | |||
0a22f80942 | |||
fb247197e8 | |||
261ed05fa3 | |||
f5ce48a7c2 | |||
82d128974c | |||
34ae731959 | |||
030a92d048 | |||
a327358b7a | |||
9bd078d3e9 | |||
412405e22c | |||
2b20b34a74 | |||
f269a07463 | |||
d9948e8ee0 | |||
ddb2fe4b03 | |||
471f7184fb | |||
92ea5da358 | |||
09f1d3ca15 | |||
3729b8eac2 | |||
ca5f345414 | |||
15cf1e8a53 | |||
da74b0ece1 | |||
f50fe6f22f | |||
542eec2a9e | |||
4c5460fc9e | |||
394b8f1ce6 | |||
abeeda1a2b | |||
9e6ea3f486 | |||
2777a0946c | |||
7f43c2659a | |||
a4fa11c881 | |||
8230e51c05 | |||
6e62d4791c | |||
ce8abdb8cd | |||
941bb7edaa | |||
1acbdf8b9e | |||
530804c847 | |||
b00b426e9c | |||
128f1753c0 | |||
1922629d27 | |||
283a03a7cc | |||
cdab26a97b | |||
5d3311c46b | |||
7cbc21671b | |||
d14d820e25 | |||
b567d02df2 | |||
dbb58541f2 | |||
5a42caf4f8 | |||
c2acd010ce | |||
4a8bcc6f71 | |||
89e4dc7a08 | |||
c344eedb12 | |||
0aeb1a62b9 | |||
316e0f5a68 | |||
6f9314f76f | |||
6ef21795ba | |||
e44855493e | |||
101a3c8af5 | |||
8fbbbce4ec | |||
1de8bb850f | |||
25d09186fe | |||
9552b7c6f9 | |||
3d692e4198 | |||
215ca9f755 | |||
7dbcb24f3d | |||
18b4bd62f7 | |||
20f3cf5327 | |||
c1d35e8af5 | |||
e1cd318f61 | |||
4da0952091 | |||
a60f75f0a9 | |||
3814009ad9 | |||
fe7bb00112 | |||
2356753dfc | |||
bd23ec268b | |||
1d5f23c3c7 | |||
f424bf53b3 | |||
efbdf0006e | |||
625b173ee4 | |||
0a8d9bc3d3 | |||
0d0909a461 | |||
ebb0a538f8 | |||
337a566617 | |||
fecee7a12b | |||
282ec99ce8 | |||
17a4985ebe | |||
13b17d91a9 | |||
5782005007 | |||
258f2dbe8f | |||
e7b35bd0c2 | |||
176bd229e6 | |||
c12f1251b0 | |||
0710736661 | |||
51ebe520f4 | |||
1ef566c824 | |||
96cf06fe8d | |||
38ebfdcd0c | |||
b5649e2a6f | |||
5fc6dadeae | |||
22cfec9276 | |||
0a82ec5f0a | |||
3bdd1f6c4f | |||
1e466dc1fe | |||
3b302d2f86 | |||
7f108eebf9 | |||
9d41fee2fe | |||
bef686f95a | |||
4bdcb974bd | |||
af042bd23c | |||
19e3cef7dd | |||
085ab4bfb4 | |||
f7bd03d051 | |||
b48d751717 | |||
92a4a1b210 | |||
6a57fcc04a | |||
749e11762f | |||
61817726c3 | |||
808354e969 | |||
d2f594ff4a | |||
fa18467cdd | |||
4c940d02ef | |||
04202a6b70 | |||
4483901270 | |||
f02d894697 | |||
2bc130856a | |||
aa3a4dca65 | |||
4f65931f51 | |||
93be61e483 | |||
cb7fe364bc | |||
9cdcb4b22c | |||
c49072f9b6 | |||
61df26b667 | |||
25c935f1db | |||
6b982bc0c7 | |||
caccc803d3 | |||
5be640632b | |||
40912f0ffd | |||
d518860a34 | |||
185617ed9e | |||
5ba96b627e | |||
edf955f4cd | |||
8d0b04668e | |||
a72e5e02da | |||
4740404c2e | |||
34253916ea | |||
1d77ba2694 | |||
765041c587 | |||
8c6bca7666 | |||
c1b1cef590 | |||
507f7804c3 | |||
453bacf9bd | |||
25778458c6 | |||
7a42646bed | |||
755b7034d2 | |||
122fcfd701 | |||
2c905eddc2 | |||
3e8eb9abb5 | |||
d2df3b2d9a | |||
2a0c983c2e | |||
1319432fde | |||
02e2aeb6d1 | |||
5e35edd976 | |||
4d63c6266c | |||
48f8d41993 | |||
0b41ccad83 | |||
f994afbc11 | |||
5dea783677 | |||
347ef9a1d0 | |||
739aa5311c | |||
805018286c | |||
45f2a47ba5 | |||
fe503b7bee | |||
6736570ee7 | |||
88c06eea6e | |||
13693ef9e5 | |||
3a54326e73 | |||
941c1c8a45 | |||
f56e102f20 | |||
010c669ce2 | |||
d328058075 | |||
9609e7b297 | |||
92718372b8 | |||
9108eb5616 | |||
354ad9d0d5 | |||
100b92036b | |||
e9ed1ecc8c | |||
92595ccc35 | |||
ea45044dc7 | |||
1ef28494b3 | |||
985d324593 | |||
96e7178cd2 | |||
f41e2358a9 | |||
0f146ff355 | |||
465f241e89 | |||
2bdb011240 | |||
dd55725f9b | |||
6b16808207 | |||
411111fa55 | |||
5345a12aca | |||
39adcde16d | |||
3c37ee60af | |||
4effc4dd60 | |||
fec9fa17e8 | |||
4071b285ce | |||
fca306ffa6 | |||
0e042925f2 | |||
99421846c7 | |||
592885ff6c | |||
a95306c317 | |||
8bdbf7b994 | |||
7bc80f0814 | |||
aed65d2594 | |||
63b3e4d90d | |||
f9c459eab2 | |||
a6d83149a4 | |||
387b477034 | |||
68cdcd193c | |||
08438c7725 | |||
1894b46d3a | |||
367a825955 | |||
be799eb254 | |||
4820a27016 | |||
6b57202421 | |||
4e82212956 | |||
6b0f5ed12d | |||
0a258caf48 | |||
f546a68f7c | |||
1e5bab09db | |||
35fa18a852 | |||
90c1eeb312 | |||
404c32b49b | |||
c0f4cd2097 | |||
fa98908dea | |||
23e8567e86 | |||
ca3edb6687 | |||
a02e28f493 | |||
7428f87899 | |||
d6a7e32ca9 | |||
df0f562817 | |||
0dea2bc79e | |||
02481560a9 | |||
dc1d1015ed | |||
59fffbd3ee | |||
655cbca574 | |||
e22c28a3c9 | |||
e823e371f6 | |||
feae7d6269 | |||
e1c0ea0720 | |||
4e1a389c8b | |||
0362a6a3dc | |||
3891dea009 | |||
2d66063763 | |||
1ccb7e2092 | |||
62ad99d0b6 | |||
66d07fbed3 | |||
ec117adb2d | |||
3aff31b826 | |||
1621944105 | |||
16d0d11e0b | |||
9158e24295 | |||
0b81f28e99 | |||
2ccb814223 | |||
f213abd70a | |||
b87eddeeda | |||
92fc56e70d | |||
e22f3238fb | |||
c597c4c234 | |||
5973c3d1a0 | |||
118e177756 | |||
d50472cd7b | |||
11604bbcfd | |||
cf428598d5 | |||
a45fc0c4df | |||
88ac82a013 | |||
5abf0df154 | |||
9a3b458c45 | |||
1b2de37c4e | |||
f7338bf00e | |||
bad7be39a6 | |||
40459defa4 | |||
b7de4b81a6 | |||
563695cdfa | |||
fd30112ee8 | |||
a36794b98b | |||
e52653469d | |||
b61035a3a3 | |||
b3039e71be | |||
c025013ca8 | |||
2c614f3bb6 | |||
07a27b25e0 | |||
4c080572ac | |||
95cd6ea48e | |||
2e3c57226f | |||
69f7367a18 | |||
8ff7f0bf5e | |||
e2a9470f31 | |||
a2a64e73bc | |||
15305e3a0b | |||
bcb484ba62 | |||
278fd8023b | |||
ba7efb45e7 | |||
8d3d218067 | |||
5185934f25 | |||
0a9cbfd0e5 | |||
35e237b5b3 | |||
ba18cd505b | |||
662df53a10 | |||
eadf2e89a8 | |||
a3b54b9891 | |||
18cab2c759 | |||
8edc4fd67a | |||
b914163499 | |||
c55c8bff6e | |||
e669bb1f82 | |||
452c3fd355 | |||
60be0c92da | |||
03bd88a2d5 | |||
7f355698bc | |||
22ec675cec | |||
3954c482ce | |||
d06feec37b | |||
536af96ccc | |||
e1a8d3db54 | |||
83d51a85ce | |||
4400744f35 | |||
ea4b85ad54 | |||
60b6a9ce47 | |||
927e00bd66 | |||
cd8d2dd8f3 | |||
6861965779 | |||
8a9a1d7df7 | |||
e7e66699b1 | |||
681321feeb | |||
a637b6d4d0 | |||
97026746f8 | |||
5161ade786 | |||
6dd62a164e | |||
3bece7599c | |||
b2f3a53980 | |||
cea31a8573 | |||
ce6647a84a | |||
d54ba9a5c6 | |||
1e18d913e0 | |||
ef8c47a49f | |||
0041c7d3b3 | |||
f6cca5cb35 | |||
fa5abbf96f | |||
2ff365765d | |||
ee31e4a411 | |||
ee4068d671 | |||
5e86c95db6 | |||
6126624631 | |||
a320e4d48d | |||
a7c5841e76 | |||
0f242a94b4 | |||
8f8a0897e4 | |||
7c6b64123c | |||
55642093ed | |||
5660f40512 | |||
3259b7183b | |||
df7cd648ac | |||
2a5713ed67 | |||
b7c36c07c6 | |||
de93281f3e | |||
86fbdced1b | |||
43bcfb9a4e | |||
0daf6af3b8 | |||
c3bccbade8 | |||
3261628da4 | |||
1e39f48235 | |||
05b5d9da9b | |||
3491dde94a | |||
db2aa920e2 | |||
8067b2e634 | |||
273c6d7dee | |||
4d0149a4a0 | |||
d9f3db5bf3 | |||
c8a679ecce | |||
3abe47ae9e | |||
725a8dc237 | |||
fcb05a7834 | |||
02e22df4d5 | |||
694c0af146 | |||
8bfca2f10a | |||
6bea9a087c | |||
3f4218f75f | |||
3849f59126 | |||
239b12cbb0 | |||
8ccee87378 | |||
9e518ffc4c | |||
e3233fd19f | |||
d3af9b0f14 | |||
08daca848b | |||
c5da8e3b10 | |||
3b0ffde1fb | |||
6ca97e8d5d | |||
34a727b435 | |||
6a9c865fec | |||
b1b9100600 | |||
bda0943d58 | |||
ad6db71f7e | |||
b21d202c7f | |||
3ea8ea1e3b | |||
ee897a9973 | |||
bb9ea3f60f | |||
5f8cfb9977 | |||
d7928a70bf | |||
93568af5a9 | |||
9e86d97253 | |||
84bac0c462 | |||
3c18a258ff | |||
9759c68d58 | |||
f57a190405 | |||
d2eb203aa1 | |||
dd2c2dbe61 | |||
2529592b66 | |||
f248d2fe4e | |||
875bcd8ce2 | |||
726f9375e1 | |||
0c2e200245 | |||
a10db462eb | |||
6df28d8171 | |||
8367f15638 | |||
69456d3569 | |||
3b644338bc | |||
02e29aa22f | |||
88c489a585 | |||
706e73210d | |||
d52809c914 | |||
6058286577 | |||
a271f24157 | |||
2299375aaa | |||
c3290526a4 | |||
a9d871e9af | |||
5eb25796ca | |||
5d650bd276 | |||
b6be519537 | |||
160477d612 | |||
4a89403c37 | |||
e54cfa629e | |||
b2bc09be16 | |||
2f5d1cebb0 | |||
e4d144651e | |||
ce56dfc239 | |||
ad4f8fd7a0 | |||
c4070cb603 | |||
75c9322f75 | |||
602fd7d658 | |||
818fd2fb43 | |||
e4912fcb09 | |||
3692ec49c1 | |||
9a1ea3f375 | |||
10a754642a | |||
bc9de5d094 | |||
9f93476167 | |||
f61492d353 | |||
50cf67546b | |||
41d83ec421 | |||
cc9377b37d | |||
7f986d5f60 | |||
d272bf8a29 | |||
ba5260f5b1 | |||
40c788fc33 | |||
7eca15d50f | |||
8f147e7de2 | |||
85358c7dd4 | |||
87c7eafb87 | |||
613f4848da | |||
3cb06e4819 | |||
811701ef7f | |||
c14dc67d8a | |||
867767f009 | |||
640216d076 | |||
3a1f378e2d | |||
6b7c61f228 | |||
28ba2c00fc | |||
b56daae321 | |||
b57450398c | |||
0c25cf0ec5 | |||
c3d884e895 | |||
7a21f96552 | |||
55cfbb721b | |||
4ccb4c636f | |||
0d5c3a3a0c | |||
6bc1507114 | |||
b093cbff15 | |||
30cb8ec9c3 | |||
d5e51d6c38 | |||
6f0a6c7f69 | |||
549d71073e | |||
4ad5522f9e | |||
2145c1a48c | |||
0f093b1238 | |||
1aa3fd7056 | |||
cc4c47c3ee | |||
6e3f3fac9d | |||
261adefbc7 | |||
7eafcfd7ad | |||
6183d6a22e | |||
51d42692ba | |||
18a9c059f4 | |||
50a13ffd6d | |||
b360944742 | |||
59d1a47846 | |||
22969d8daa | |||
95ba87945b | |||
63aeee8b22 | |||
da11a86f99 | |||
98c2f012ee | |||
386c6144f8 | |||
666f9c2db9 | |||
f7c49588fb | |||
c0e6f06a5c | |||
6668c8ff66 | |||
31907f2d16 | |||
452d0af8c9 | |||
c5a28f3601 | |||
d13f26dc7e | |||
03374483e4 | |||
b1c0a865a0 | |||
7b0799a6f6 | |||
0de2976933 | |||
20c7bf3c48 | |||
55e090ba2a | |||
ded326c822 | |||
1ee9c2cf0e | |||
e41d9008b3 | |||
1ec24251a2 | |||
2be48c3847 | |||
2137b79f6d | |||
0b8086bd36 | |||
d16659890c | |||
076d150f72 | |||
62deffd017 | |||
f1ec70ff14 | |||
af27c763e0 | |||
7336417634 | |||
cde46c0889 | |||
5da4dadc31 | |||
e32ca089ec | |||
8d2f644177 | |||
a003010be5 | |||
89ada83012 | |||
65fbf6926c | |||
5e652364c9 | |||
8b7c3d6cfa | |||
3b214a0105 | |||
c0c4073bc4 | |||
dbe7324c7f | |||
9316255e87 | |||
7f7dff7019 | |||
961e004a49 | |||
02c1e4fb65 | |||
bcbc2a6e95 | |||
0c749a126c | |||
3698ebad7c | |||
f59a5c90a5 | |||
36e4a69891 | |||
19b560f7c1 | |||
0bec92e87e | |||
a0d02f16cd | |||
4a0f655e1c | |||
91bf65292d | |||
a69d52d688 | |||
79fe224cea | |||
757d8e59a2 | |||
53ec1416b4 | |||
e5add21612 | |||
d1b52534de | |||
35edc053b5 | |||
2aa8d3be0f | |||
a20c2aa996 | |||
f8c1fde358 | |||
113658f3f7 | |||
c54a48865b | |||
4c4e94dba0 | |||
ec142cbbe1 | |||
702ff964fe | |||
919439977c | |||
a6478c5146 | |||
524c4ab5a1 | |||
3c795eec7c | |||
b9e352cbcb | |||
e23744a0d0 | |||
626528fa5e | |||
274cde1c21 | |||
4c8cb31a6f | |||
bea89be67b | |||
4cb17de82a | |||
da3a4d5855 | |||
b0c5d1e991 | |||
231fb80c2c | |||
c49af06e57 | |||
79fc03bb0f |
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
Oqtane.Server/wwwroot/Modules/Templates/External/Package/*.sh eol=lf
|
||||
Oqtane.Server/wwwroot/Themes/Templates/External/Package/*.sh eol=lf
|
@ -1,6 +1,8 @@
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@inject IInstallationService InstallationService
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject SiteState SiteState
|
||||
@inject IServiceProvider ServiceProvider
|
||||
|
||||
@if (_initialized)
|
||||
{
|
||||
@ -30,35 +32,47 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string AntiForgeryToken { get; set; }
|
||||
[Parameter]
|
||||
public string AntiForgeryToken { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string RemoteIPAddress { get; set; }
|
||||
[Parameter]
|
||||
public string RemoteIPAddress { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string AuthorizationToken { get; set; }
|
||||
[Parameter]
|
||||
public string AuthorizationToken { get; set; }
|
||||
|
||||
private bool _initialized = false;
|
||||
private string _display = "display: none;";
|
||||
private Installation _installation = new Installation { Success = false, Message = "" };
|
||||
private bool _initialized = false;
|
||||
private string _display = "display: none;";
|
||||
private Installation _installation = new Installation { Success = false, Message = "" };
|
||||
|
||||
private PageState PageState { get; set; }
|
||||
private PageState PageState { get; set; }
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
SiteState.RemoteIPAddress = RemoteIPAddress;
|
||||
SiteState.AntiForgeryToken = AntiForgeryToken;
|
||||
SiteState.AuthorizationToken = AuthorizationToken;
|
||||
private IHttpContextAccessor accessor;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
SiteState.RemoteIPAddress = RemoteIPAddress;
|
||||
SiteState.AntiForgeryToken = AntiForgeryToken;
|
||||
SiteState.AuthorizationToken = AuthorizationToken;
|
||||
|
||||
accessor = (IHttpContextAccessor)ServiceProvider.GetService(typeof(IHttpContextAccessor));
|
||||
if (accessor != null)
|
||||
{
|
||||
SiteState.IsPrerendering = !accessor.HttpContext.Response.HasStarted;
|
||||
}
|
||||
else
|
||||
{
|
||||
SiteState.IsPrerendering = true;
|
||||
}
|
||||
|
||||
_installation = await InstallationService.IsInstalled();
|
||||
if (_installation.Alias != null)
|
||||
@ -72,6 +86,7 @@
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
// prevents flash on initial page load
|
||||
_display = "";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
64
Oqtane.Client/Head.razor
Normal file
64
Oqtane.Client/Head.razor
Normal file
@ -0,0 +1,64 @@
|
||||
@using System.ComponentModel
|
||||
@using Oqtane.Shared
|
||||
@inject SiteState SiteState
|
||||
|
||||
@if (!string.IsNullOrEmpty(_title))
|
||||
{
|
||||
@((MarkupString)_title)
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(_content))
|
||||
{
|
||||
@((MarkupString)_content)
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _title = "";
|
||||
private string _content = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
((INotifyPropertyChanged)SiteState.Properties).PropertyChanged += PropertyChanged;
|
||||
}
|
||||
|
||||
private void PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case "PageTitle":
|
||||
var title = "\n<title>" + SiteState.Properties.PageTitle + "</title>";
|
||||
if (title != _title)
|
||||
{
|
||||
_title = title;
|
||||
StateHasChanged();
|
||||
}
|
||||
break;
|
||||
case "HeadContent":
|
||||
var content = RemoveScripts(SiteState.Properties.HeadContent) + "\n";
|
||||
if (content != _content)
|
||||
{
|
||||
_content = content;
|
||||
StateHasChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private string RemoveScripts(string headcontent)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(headcontent))
|
||||
{
|
||||
var index = headcontent.IndexOf("<script");
|
||||
while (index >= 0)
|
||||
{
|
||||
headcontent = headcontent.Remove(index, headcontent.IndexOf("</script>") + 9 - index);
|
||||
index = headcontent.IndexOf("<script");
|
||||
}
|
||||
}
|
||||
return headcontent;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
((INotifyPropertyChanged)SiteState.Properties).PropertyChanged -= PropertyChanged;
|
||||
}
|
||||
}
|
14
Oqtane.Client/IconResources.cs
Normal file
14
Oqtane.Client/IconResources.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace Oqtane
|
||||
{
|
||||
/// <summary>
|
||||
/// Dummy class used to collect shared resource strings for this application
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is mostly used with IStringLocalizer and IHtmlLocalizer interfaces.
|
||||
/// The class must reside at the project root.
|
||||
/// </remarks>
|
||||
public class IconResources
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
@namespace Oqtane.Installer.Controls
|
||||
@implements Oqtane.Interfaces.IDatabaseConfigControl
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="server" HelpText="Enter the database server" ResourceKey="Server">Server:</Label>
|
||||
@ -28,7 +29,10 @@
|
||||
<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">
|
||||
<input id="pwd" type="password" class="form-control" @bind="@_pwd" autocomplete="new-password" />
|
||||
<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>
|
||||
|
||||
@ -38,6 +42,13 @@
|
||||
private string _database = "Oqtane-" + DateTime.UtcNow.ToString("yyyyMMddHHmm");
|
||||
private string _uid = String.Empty;
|
||||
private string _pwd = String.Empty;
|
||||
private string _passwordType = "password";
|
||||
private string _togglePassword = string.Empty;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
|
||||
public string GetConnectionString()
|
||||
{
|
||||
@ -55,4 +66,18 @@
|
||||
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordType == "password")
|
||||
{
|
||||
_passwordType = "text";
|
||||
_togglePassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordType = "password";
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
@namespace Oqtane.Installer.Controls
|
||||
@implements Oqtane.Interfaces.IDatabaseConfigControl
|
||||
@inject IStringLocalizer<PostgreSQLConfig> 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" ResourceKey="Server">Server:</Label>
|
||||
@ -40,7 +41,10 @@
|
||||
<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">
|
||||
<input id="pwd" type="password" class="form-control" @bind="@_pwd" autocomplete="new-password" />
|
||||
<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>
|
||||
}
|
||||
@ -52,6 +56,13 @@
|
||||
private string _security = "integrated";
|
||||
private string _uid = String.Empty;
|
||||
private string _pwd = String.Empty;
|
||||
private string _passwordType = "password";
|
||||
private string _togglePassword = string.Empty;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
|
||||
public string GetConnectionString()
|
||||
{
|
||||
@ -80,4 +91,18 @@
|
||||
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordType == "password")
|
||||
{
|
||||
_passwordType = "text";
|
||||
_togglePassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordType = "password";
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
@ -35,7 +35,10 @@
|
||||
<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">
|
||||
<input id="pwd" type="password" class="form-control" @bind="@_pwd" autocomplete="new-password" />
|
||||
<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>
|
||||
}
|
||||
@ -67,9 +70,16 @@
|
||||
private string _security = "integrated";
|
||||
private string _uid = String.Empty;
|
||||
private string _pwd = String.Empty;
|
||||
private string _passwordType = "password";
|
||||
private string _togglePassword = string.Empty;
|
||||
private string _encryption = "false";
|
||||
private string _trustservercertificate = "false";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
|
||||
public string GetConnectionString()
|
||||
{
|
||||
var connectionString = String.Empty;
|
||||
@ -92,4 +102,18 @@
|
||||
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordType == "password")
|
||||
{
|
||||
_passwordType = "text";
|
||||
_togglePassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordType = "password";
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
@ -5,15 +5,17 @@
|
||||
@inject ISiteService SiteService
|
||||
@inject IUserService UserService
|
||||
@inject IDatabaseService DatabaseService
|
||||
@inject ISiteTemplateService SiteTemplateService
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject IStringLocalizer<Installer> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
@inject SiteState SiteState
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="mx-auto text-center">
|
||||
<img src="oqtane-black.png" />
|
||||
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version</div>
|
||||
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET 7)</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="app-rule" />
|
||||
@ -61,7 +63,7 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<h2>@Localizer["ApplicationAdmin"]</h2><br />
|
||||
@ -96,6 +98,20 @@
|
||||
<input type="text" class="form-control" @bind="@_hostEmail" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="template" HelpText="Select a site template" ResourceKey="Template">Template:</Label>
|
||||
<div class="col-sm-9">
|
||||
@if (_templates != null)
|
||||
{
|
||||
<select id="template" class="form-select" @bind="@_template" required>
|
||||
@foreach (var template in _templates)
|
||||
{
|
||||
<option value="@template.TypeName">@template.Name</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -103,7 +119,13 @@
|
||||
<div class="row">
|
||||
<div class="mx-auto text-center">
|
||||
<button type="button" class="btn btn-success" @onclick="Install">@Localizer["InstallNow"]</button><br /><br />
|
||||
<ModuleMessage Message="@_message" Type="MessageType.Error"></ModuleMessage>
|
||||
@if (!string.IsNullOrEmpty(_message))
|
||||
{
|
||||
<div class="alert alert-danger alert-dismissible fade show mb-3" role="alert">
|
||||
@((MarkupString)_message)
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="DismissModal"></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="app-progress-indicator" style="@_loadingDisplay"></div>
|
||||
</div>
|
||||
@ -115,29 +137,35 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private List<Database> _databases;
|
||||
private string _databaseName;
|
||||
private Type _databaseConfigType;
|
||||
private object _databaseConfig;
|
||||
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||
private bool _showConnectionString = false;
|
||||
private string _connectionString = string.Empty;
|
||||
private List<Database> _databases;
|
||||
private string _databaseName;
|
||||
private Type _databaseConfigType;
|
||||
private object _databaseConfig;
|
||||
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||
private bool _showConnectionString = false;
|
||||
private string _connectionString = string.Empty;
|
||||
|
||||
private string _hostUsername = string.Empty;
|
||||
private string _hostPassword = string.Empty;
|
||||
private string _passwordType = "password";
|
||||
private string _confirmPasswordType = "password";
|
||||
private string _togglePassword = string.Empty;
|
||||
private string _toggleConfirmPassword = string.Empty;
|
||||
private string _confirmPassword = string.Empty;
|
||||
private string _hostEmail = string.Empty;
|
||||
private bool _register = true;
|
||||
private string _hostUsername = string.Empty;
|
||||
private string _hostPassword = string.Empty;
|
||||
private string _passwordType = "password";
|
||||
private string _confirmPasswordType = "password";
|
||||
private string _togglePassword = string.Empty;
|
||||
private string _toggleConfirmPassword = string.Empty;
|
||||
private string _confirmPassword = string.Empty;
|
||||
private string _hostEmail = string.Empty;
|
||||
private List<SiteTemplate> _templates;
|
||||
private string _template = Constants.DefaultSiteTemplate;
|
||||
private bool _register = true;
|
||||
private string _message = string.Empty;
|
||||
private string _loadingDisplay = "display: none;";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
// include CSS
|
||||
var content = "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css\" integrity=\"sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==\" crossorigin=\"anonymous\" type=\"text/css\"/>";
|
||||
SiteState.AppendHeadContent(content);
|
||||
|
||||
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
|
||||
|
||||
_databases = await DatabaseService.GetDatabasesAsync();
|
||||
@ -150,7 +178,9 @@
|
||||
_databaseName = "LocalDB";
|
||||
}
|
||||
LoadDatabaseConfigComponent();
|
||||
}
|
||||
|
||||
_templates = await SiteTemplateService.GetSiteTemplatesAsync();
|
||||
}
|
||||
|
||||
private void DatabaseChanged(ChangeEventArgs eventArgs)
|
||||
{
|
||||
@ -185,9 +215,9 @@
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
// include JavaScript
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.0/css/bootstrap.min.css", "text/css", "sha512-XWTTruHZEYJsxV3W/lSXG1n3Q39YIWOstqvmFsdNEEQfHoZ6vm6E9GK2OrF6DSJSpIbRbi+Nn0WDPID9O7xB2Q==", "anonymous", "");
|
||||
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.0/js/bootstrap.bundle.min.js", "sha512-9GacT4119eY3AcosfWtHMsT5JyZudrexyEVzTBWV3viP/YfB9e2pEy3N7WXL3SV6ASXpTU0vzzSxsbfsuUH4sQ==", "anonymous", "", "head");
|
||||
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js", "sha512-VK2zcvntEufaimc+efOYi622VN5ZacdnufnmX7zIhCPmjhKnOi9ZDMtg1/ug5l183f19gG1/cBstPO4D8N/Img==", "anonymous", "", "head");
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +259,8 @@
|
||||
TenantName = TenantNames.Master,
|
||||
IsNewTenant = true,
|
||||
SiteName = Constants.DefaultSite,
|
||||
Register = _register
|
||||
Register = _register,
|
||||
SiteTemplate = _template
|
||||
};
|
||||
|
||||
var installation = await InstallationService.Install(config);
|
||||
@ -291,4 +322,9 @@
|
||||
_showConnectionString = !_showConnectionString;
|
||||
}
|
||||
|
||||
private void DismissModal()
|
||||
{
|
||||
_message = "";
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,12 @@
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
{
|
||||
string url = NavigateUrl(p.Path);
|
||||
<div class="col-md-2 mx-auto text-center mb-3">
|
||||
<p class="col-md-2 mx-auto text-center mb-3">
|
||||
<NavLink class="nav-link text-primary" href="@url" Match="NavLinkMatch.All">
|
||||
<h2><span class="@p.Icon" aria-hidden="true"></span></h2>@SharedLocalizer[p.Name]
|
||||
<h2><span class="@p.Icon" aria-hidden="true"></span></h2>
|
||||
<p class="lead">@((MarkupString)SharedLocalizer[p.Name].ToString().Replace(" ", "<br />"))</p>
|
||||
</NavLink>
|
||||
</div>
|
||||
</p>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
@ -48,7 +48,7 @@
|
||||
</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,x200,200x)" ResourceKey="ImageSizes">Image Sizes: </Label>
|
||||
<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>
|
||||
@ -67,6 +67,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<br /><br />
|
||||
|
||||
@if (!_isSystem)
|
||||
{
|
||||
@ -79,8 +80,7 @@
|
||||
@((MarkupString)" ")
|
||||
<ActionDialog Header="Delete Folder" Message="Are You Sure You Wish To Delete This Folder?" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFolder())" ResourceKey="DeleteFolder" />
|
||||
}
|
||||
<br />
|
||||
<br />
|
||||
<br /><br />
|
||||
@if (PageState.QueryString.ContainsKey("id"))
|
||||
{
|
||||
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
|
||||
@ -110,7 +110,7 @@
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
public override string Title => "Folder Management";
|
||||
public override string Title => "Folder Management";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
|
@ -8,27 +8,28 @@
|
||||
|
||||
@if (_files != null)
|
||||
{
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-2">
|
||||
<label class="control-label">@Localizer["Folder"] </label>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="row">
|
||||
<div class="col-md mb-1">
|
||||
<ActionLink Action="Edit" Text="Add Folder" Class="btn btn-secondary" ResourceKey="AddFolder" />
|
||||
</div>
|
||||
<div class="col-md-8 mb-1">
|
||||
<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>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<ActionLink Action="Edit" Text="Edit Folder" Class="btn btn-secondary" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="EditFolder" />
|
||||
<ActionLink Action="Edit" Text="Add Folder" Class="btn btn-secondary" ResourceKey="AddFolder" />
|
||||
<ActionLink Action="Add" Text="Upload Files" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="UploadFiles" />
|
||||
</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">
|
||||
|
||||
<Pager Items="@_files" SearchProperties="Name">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
|
@ -56,7 +56,7 @@
|
||||
<input id="starting" type="date" class="form-control" @bind="@_startDate" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<input id="starting" type="text" class="form-control" placeholder="hh:mm" @bind="@_startTime" />
|
||||
<input id="starting" type="time" class="form-control" placeholder="hh:mm" @bind="@_startTime" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -69,7 +69,7 @@
|
||||
<input id="ending" type="date" class="form-control" @bind="@_endDate" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<input id="ending" type="text" class="form-control" placeholder="hh:mm" @bind="@_endTime" />
|
||||
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -82,7 +82,7 @@
|
||||
<input id="next" type="date" class="form-control" @bind="@_nextDate" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<input id="next" type="text" class="form-control" placeholder="hh:mm" @bind="@_nextTime" />
|
||||
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -97,22 +97,22 @@
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private int _jobId;
|
||||
private string _name = string.Empty;
|
||||
private string _jobType = string.Empty;
|
||||
private string _isEnabled = "True";
|
||||
private string _interval = string.Empty;
|
||||
private string _frequency = string.Empty;
|
||||
private DateTime? _startDate = null;
|
||||
private string _startTime = string.Empty;
|
||||
private DateTime? _endDate = null;
|
||||
private string _endTime = string.Empty;
|
||||
private string _retentionHistory = string.Empty;
|
||||
private DateTime? _nextDate = null;
|
||||
private string _nextTime = string.Empty;
|
||||
private string createdby;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private int _jobId;
|
||||
private string _name = string.Empty;
|
||||
private string _jobType = string.Empty;
|
||||
private string _isEnabled = "True";
|
||||
private string _interval = string.Empty;
|
||||
private string _frequency = string.Empty;
|
||||
private DateTime? _startDate = null;
|
||||
private DateTime? _startTime = null;
|
||||
private DateTime? _endDate = null;
|
||||
private DateTime? _endTime = null;
|
||||
private string _retentionHistory = string.Empty;
|
||||
private DateTime? _nextDate = null;
|
||||
private DateTime? _nextTime = null;
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
@ -132,11 +132,14 @@
|
||||
_isEnabled = job.IsEnabled.ToString();
|
||||
_interval = job.Interval.ToString();
|
||||
_frequency = job.Frequency;
|
||||
(_startDate, _startTime) = Utilities.UtcAsLocalDateAndTime(job.StartDate);
|
||||
(_endDate, _endTime) = Utilities.UtcAsLocalDateAndTime(job.EndDate);
|
||||
_retentionHistory = job.RetentionHistory.ToString();
|
||||
(_nextDate, _nextTime) = Utilities.UtcAsLocalDateAndTime(job.NextExecution);
|
||||
createdby = job.CreatedBy;
|
||||
_startDate = Utilities.UtcAsLocalDate(job.StartDate);
|
||||
_startTime = Utilities.UtcAsLocalDateTime(job.StartDate);
|
||||
_endDate = Utilities.UtcAsLocalDate(job.EndDate);
|
||||
_endTime = Utilities.UtcAsLocalDateTime(job.EndDate);
|
||||
_retentionHistory = job.RetentionHistory.ToString();
|
||||
_nextDate = Utilities.UtcAsLocalDate(job.NextExecution);
|
||||
_nextTime = Utilities.UtcAsLocalDateTime(job.NextExecution);
|
||||
createdby = job.CreatedBy;
|
||||
createdon = job.CreatedOn;
|
||||
modifiedby = job.ModifiedBy;
|
||||
modifiedon = job.ModifiedOn;
|
||||
|
@ -11,11 +11,11 @@
|
||||
else
|
||||
{
|
||||
<ActionLink Action="Log" Class="btn btn-secondary" Text="View Logs" ResourceKey="ViewJobs" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="(async () => await Refresh())">Refresh</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="(async () => await Refresh())">@Localizer["Refresh.Text"]</button>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<Pager Items="@_jobs">
|
||||
<Pager Items="@_jobs" SearchProperties="Name">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
|
@ -16,7 +16,7 @@
|
||||
else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Manage" ResourceKey="Manage">
|
||||
<TabPanel Name="Manage" ResourceKey="Manage" Heading="Manage">
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -45,7 +45,7 @@ else
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</form>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host">
|
||||
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host" Heading="Upload">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" HelpText="Upload one or more translations. Once they are uploaded click Install." ResourceKey="LanguageUpload">Translation: </Label>
|
||||
|
@ -14,7 +14,7 @@ else
|
||||
{
|
||||
<ActionLink Action="Add" Text="Add Language" ResourceKey="AddLanguage" />
|
||||
|
||||
<Pager Items="@_languages">
|
||||
<Pager Items="@_languages" SearchProperties="Name,Code">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
@ -22,7 +22,7 @@ else
|
||||
<th>@Localizer["Default"]</th>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<th style="width: 1px;">@Localizer["Translation"]</th>
|
||||
<th style="width: 1px;">@Localizer["Translation"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
}
|
||||
</Header>
|
||||
@ -33,7 +33,7 @@ else
|
||||
<td><TriStateCheckBox Value="@(context.IsDefault)" Disabled="true"></TriStateCheckBox></td>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
|
||||
<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
|
||||
<td>
|
||||
@{
|
||||
var translation = TranslationAvailable(context.Code, context.Version);
|
||||
@ -99,56 +99,64 @@ else
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<Language> _languages;
|
||||
private List<Package> _packages;
|
||||
private Package _package;
|
||||
private List<Language> _languages;
|
||||
private List<Package> _packages;
|
||||
private Package _package;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await GetLanguages();
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await GetLanguages();
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_packages = await PackageService.GetPackagesAsync("translation");
|
||||
}
|
||||
}
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_packages = await PackageService.GetPackagesAsync("translation");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetLanguages()
|
||||
{
|
||||
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId, Constants.ClientId);
|
||||
}
|
||||
private async Task GetLanguages()
|
||||
{
|
||||
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId, Constants.ClientId);
|
||||
}
|
||||
|
||||
private async Task DeleteLanguage(Language language)
|
||||
{
|
||||
try
|
||||
{
|
||||
await LanguageService.DeleteLanguageAsync(language.LanguageId);
|
||||
await logger.LogInformation("Language Deleted {Language}", language);
|
||||
await GetLanguages();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Language {Language} {Error}", language, ex.Message);
|
||||
private async Task DeleteLanguage(Language language)
|
||||
{
|
||||
try
|
||||
{
|
||||
await LanguageService.DeleteLanguageAsync(language.LanguageId);
|
||||
await logger.LogInformation("Language Deleted {Language}", language);
|
||||
await GetLanguages();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Language {Language} {Error}", language, ex.Message);
|
||||
|
||||
AddModuleMessage(Localizer["Error.Language.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
AddModuleMessage(Localizer["Error.Language.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private Package TranslationAvailable(string code, string version)
|
||||
{
|
||||
return _packages?.FirstOrDefault(item => item.PackageId == (Constants.PackageId + "." + code));
|
||||
}
|
||||
private Package TranslationAvailable(string code, string version)
|
||||
{
|
||||
return _packages?.FirstOrDefault(item => item.PackageId == (Constants.PackageId + "." + code));
|
||||
}
|
||||
|
||||
private async Task GetPackage(string code, string version)
|
||||
{
|
||||
try
|
||||
{
|
||||
_package = await PackageService.GetPackageAsync(Constants.PackageId + "." + code, version);
|
||||
StateHasChanged();
|
||||
}
|
||||
private async Task GetPackage(string code, string version)
|
||||
{
|
||||
try
|
||||
{
|
||||
_package = await PackageService.GetPackageAsync(Constants.PackageId + "." + code, version, false);
|
||||
if (_package != null)
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError("Error Getting Package {PackageId} {Version}", Constants.PackageId + "." + code, Constants.Version);
|
||||
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", Constants.PackageId + "." + code, Constants.Version);
|
||||
@ -160,7 +168,7 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version, Constants.PackagesFolder);
|
||||
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version);
|
||||
await logger.LogInformation("Language Package {Name} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Language.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
_package = null;
|
||||
|
@ -3,6 +3,7 @@
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserService UserService
|
||||
@inject ISettingService SettingService
|
||||
@inject IServiceProvider ServiceProvider
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
@ -11,9 +12,6 @@
|
||||
<Authorizing>
|
||||
<text>...</text>
|
||||
</Authorizing>
|
||||
<Authorized>
|
||||
<div>@Localizer["Info.SignedIn"]</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
@if (!twofactor)
|
||||
{
|
||||
@ -69,259 +67,264 @@
|
||||
</AuthorizeView>
|
||||
|
||||
@code {
|
||||
private bool _allowsitelogin = true;
|
||||
private bool _allowexternallogin = false;
|
||||
private ElementReference login;
|
||||
private bool validated = false;
|
||||
private bool twofactor = false;
|
||||
private string _username = string.Empty;
|
||||
private ElementReference username;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private bool _remember = false;
|
||||
private string _code = string.Empty;
|
||||
private bool _allowsitelogin = true;
|
||||
private bool _allowexternallogin = false;
|
||||
private ElementReference login;
|
||||
private bool validated = false;
|
||||
private bool twofactor = false;
|
||||
private string _username = string.Empty;
|
||||
private ElementReference username;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private bool _remember = false;
|
||||
private string _code = string.Empty;
|
||||
|
||||
private string _returnUrl = string.Empty;
|
||||
private string _returnUrl = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
||||
};
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("returnurl"))
|
||||
{
|
||||
_returnUrl = PageState.QueryString["returnurl"];
|
||||
}
|
||||
|
||||
if (PageState.Site.Settings.ContainsKey("LoginOptions:AllowSiteLogin") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:AllowSiteLogin"]))
|
||||
{
|
||||
_allowsitelogin = bool.Parse(PageState.Site.Settings["LoginOptions:AllowSiteLogin"]);
|
||||
}
|
||||
_allowexternallogin = (SettingService.GetSetting(PageState.Site.Settings, "ExternalLogin:ProviderType", "") != "") ? true : false;
|
||||
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
|
||||
|
||||
if (PageState.Site.Settings.ContainsKey("ExternalLogin:ProviderType") && !string.IsNullOrEmpty(PageState.Site.Settings["ExternalLogin:ProviderType"]))
|
||||
{
|
||||
_allowexternallogin = true;
|
||||
}
|
||||
if (_allowexternallogin && !_allowsitelogin)
|
||||
{
|
||||
// redirect to external login
|
||||
NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + _returnUrl), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PageState.QueryString.ContainsKey("returnurl"))
|
||||
{
|
||||
_returnUrl = PageState.QueryString["returnurl"];
|
||||
}
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
|
||||
if (PageState.QueryString.ContainsKey("name"))
|
||||
{
|
||||
_username = PageState.QueryString["name"];
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("name"))
|
||||
{
|
||||
_username = PageState.QueryString["name"];
|
||||
}
|
||||
|
||||
if (PageState.QueryString.ContainsKey("token") && !string.IsNullOrEmpty(_username))
|
||||
{
|
||||
var user = new User();
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = _username;
|
||||
if (PageState.QueryString.ContainsKey("token") && !string.IsNullOrEmpty(_username))
|
||||
{
|
||||
var user = new User();
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = _username;
|
||||
|
||||
if (PageState.QueryString.ContainsKey("key"))
|
||||
{
|
||||
user = await UserService.LinkUserAsync(user, PageState.QueryString["token"], PageState.Site.Settings["ExternalLogin:ProviderType"], PageState.QueryString["key"], PageState.Site.Settings["ExternalLogin:ProviderName"]);
|
||||
if (user != null)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "External Login Linkage Successful For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Success.Account.Linked"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError(LogFunction.Security, "External Login Linkage Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Message.Account.NotLinked"], MessageType.Warning);
|
||||
}
|
||||
_username = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
|
||||
if (user != null)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Email Verified For For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Success.Account.Verified"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError(LogFunction.Security, "Email Verification Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Message.Account.NotVerified"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("status"))
|
||||
{
|
||||
AddModuleMessage(Localizer["ExternalLoginStatus." + PageState.QueryString["status"]], MessageType.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Login {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadLogin"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("key"))
|
||||
{
|
||||
user = await UserService.LinkUserAsync(user, PageState.QueryString["token"], PageState.Site.Settings["ExternalLogin:ProviderType"], PageState.QueryString["key"], PageState.Site.Settings["ExternalLogin:ProviderName"]);
|
||||
if (user != null)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "External Login Linkage Successful For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Success.Account.Linked"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError(LogFunction.Security, "External Login Linkage Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Message.Account.NotLinked"], MessageType.Warning);
|
||||
}
|
||||
_username = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
|
||||
if (user != null)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Email Verified For For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Success.Account.Verified"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError(LogFunction.Security, "Email Verification Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Message.Account.NotVerified"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("status"))
|
||||
{
|
||||
AddModuleMessage(Localizer["ExternalLoginStatus." + PageState.QueryString["status"]], MessageType.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Login {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadLogin"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender && PageState.User == null)
|
||||
{
|
||||
await username.FocusAsync();
|
||||
}
|
||||
}
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender && PageState.User == null && _allowsitelogin)
|
||||
{
|
||||
await username.FocusAsync();
|
||||
}
|
||||
|
||||
private async Task Login()
|
||||
{
|
||||
try
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(login))
|
||||
{
|
||||
var hybrid = (PageState.Runtime == Shared.Runtime.Hybrid);
|
||||
var user = new User { SiteId = PageState.Site.SiteId, Username = _username, Password = _password, LastIPAddress = SiteState.RemoteIPAddress};
|
||||
|
||||
if (!twofactor)
|
||||
{
|
||||
user = await UserService.LoginUserAsync(user, hybrid, _remember);
|
||||
}
|
||||
else
|
||||
{
|
||||
user = await UserService.VerifyTwoFactorAsync(user, _code);
|
||||
}
|
||||
// redirect logged in user to specified page
|
||||
if (PageState.User != null)
|
||||
{
|
||||
NavigationManager.NavigateTo(PageState.ReturnUrl);
|
||||
}
|
||||
}
|
||||
|
||||
if (user.IsAuthenticated)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username);
|
||||
private async Task Login()
|
||||
{
|
||||
try
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(login))
|
||||
{
|
||||
var hybrid = (PageState.Runtime == Shared.Runtime.Hybrid);
|
||||
var user = new User { SiteId = PageState.Site.SiteId, Username = _username, Password = _password, LastIPAddress = SiteState.RemoteIPAddress};
|
||||
|
||||
if (hybrid)
|
||||
{
|
||||
// hybrid apps utilize an interactive login
|
||||
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider
|
||||
.GetService(typeof(IdentityAuthenticationStateProvider));
|
||||
authstateprovider.NotifyAuthenticationChanged();
|
||||
NavigationManager.NavigateTo(NavigateUrl(WebUtility.UrlDecode(_returnUrl), true));
|
||||
}
|
||||
else
|
||||
{
|
||||
// post back to the Login page so that the cookies are set correctly
|
||||
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
|
||||
string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/");
|
||||
await interop.SubmitForm(url, fields);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && PageState.Site.Settings["LoginOptions:TwoFactor"] == "required") || user.TwoFactorRequired)
|
||||
{
|
||||
twofactor = true;
|
||||
validated = false;
|
||||
AddModuleMessage(Localizer["Message.TwoFactor"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!twofactor)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Login Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Two Factor Verification Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Error.TwoFactor.Fail"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Performing Login {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Login"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
if (!twofactor)
|
||||
{
|
||||
user = await UserService.LoginUserAsync(user, hybrid, _remember);
|
||||
}
|
||||
else
|
||||
{
|
||||
user = await UserService.VerifyTwoFactorAsync(user, _code);
|
||||
}
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
NavigationManager.NavigateTo(_returnUrl);
|
||||
}
|
||||
if (user.IsAuthenticated)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username);
|
||||
|
||||
private async Task Forgot()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_username != string.Empty)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(_username, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
await UserService.ForgotPasswordAsync(user);
|
||||
await logger.LogInformation(LogFunction.Security, "Password Reset Notification Sent For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Message.ForgotUser"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.UserDoesNotExist"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.ForgotPassword"], MessageType.Info);
|
||||
}
|
||||
if (hybrid)
|
||||
{
|
||||
// hybrid apps utilize an interactive login
|
||||
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
|
||||
authstateprovider.NotifyAuthenticationChanged();
|
||||
NavigationManager.NavigateTo(NavigateUrl(WebUtility.UrlDecode(_returnUrl), true));
|
||||
}
|
||||
else
|
||||
{
|
||||
// post back to the Login page so that the cookies are set correctly
|
||||
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
|
||||
string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/");
|
||||
await interop.SubmitForm(url, fields);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "required" || user.TwoFactorRequired)
|
||||
{
|
||||
twofactor = true;
|
||||
validated = false;
|
||||
AddModuleMessage(Localizer["Message.TwoFactor"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!twofactor)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Login Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Two Factor Verification Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Error.TwoFactor.Fail"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Performing Login {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Login"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Resetting Password {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.ResetPassword"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private void Cancel()
|
||||
{
|
||||
NavigationManager.NavigateTo(_returnUrl);
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
twofactor = false;
|
||||
_username = "";
|
||||
_password = "";
|
||||
ClearModuleMessage();
|
||||
StateHasChanged();
|
||||
}
|
||||
private async Task Forgot()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_username != string.Empty)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(_username, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
await UserService.ForgotPasswordAsync(user);
|
||||
await logger.LogInformation(LogFunction.Security, "Password Reset Notification Sent For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Message.ForgotUser"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.UserDoesNotExist"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.ForgotPassword"], MessageType.Info);
|
||||
}
|
||||
|
||||
private async Task KeyPressed(KeyboardEventArgs e)
|
||||
{
|
||||
if (e.Code == "Enter" || e.Code == "NumpadEnter")
|
||||
{
|
||||
await Login();
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Resetting Password {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.ResetPassword"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordtype == "password")
|
||||
{
|
||||
_passwordtype = "text";
|
||||
_togglepassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordtype = "password";
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
private void Reset()
|
||||
{
|
||||
twofactor = false;
|
||||
_username = "";
|
||||
_password = "";
|
||||
ClearModuleMessage();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void ExternalLogin()
|
||||
{
|
||||
private async Task KeyPressed(KeyboardEventArgs e)
|
||||
{
|
||||
if (e.Code == "Enter" || e.Code == "NumpadEnter")
|
||||
{
|
||||
await Login();
|
||||
}
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordtype == "password")
|
||||
{
|
||||
_passwordtype = "text";
|
||||
_togglepassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordtype = "password";
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
|
||||
private void ExternalLogin()
|
||||
{
|
||||
NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + _returnUrl), true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="category" HelpText="The categories that were affected" ResourceKey="Category">Category: </Label>
|
||||
<Label Class="col-sm-3" For="category" HelpText="The fully qualified type type that was affected" ResourceKey="Category">Type Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="category" class="form-control" @bind="@_category" readonly />
|
||||
</div>
|
||||
|
@ -1,203 +0,0 @@
|
||||
@namespace Oqtane.Modules.Admin.ModuleCreator
|
||||
@inherits ModuleBase
|
||||
@using System.Text.RegularExpressions
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IModuleDefinitionService ModuleDefinitionService
|
||||
@inject IModuleService ModuleService
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (string.IsNullOrEmpty(_moduledefinitionname) && _templates != null)
|
||||
{
|
||||
<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="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="owner" class="form-control" @bind="@_owner" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="module" HelpText="Enter a name for this module. It should not contain spaces or punctuation." ResourceKey="ModuleName">Module Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="module" class="form-control" @bind="@_module" required />
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="description" class="form-control" @bind="@_description" rows="3" ></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="template" HelpText="Select a module template. Templates are located in the wwwroot/Modules/Templates folder on the server." ResourceKey="Template">Template: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="template" class="form-select" @onchange="(e => TemplateChanged(e))" required>
|
||||
<option value="-"><@Localizer["Template.Select"]></option>
|
||||
@foreach (Template template in _templates)
|
||||
{
|
||||
<option value="@template.Name">@template.Title</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="reference" HelpText="Select a framework reference version" ResourceKey="FrameworkReference">Framework Reference: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="reference" class="form-select" @bind="@_reference" required>
|
||||
@foreach (string version in _versions)
|
||||
{
|
||||
if (Version.Parse(version).CompareTo(Version.Parse(_minversion)) >= 0)
|
||||
{
|
||||
<option value="@(version)">@(version)</option>
|
||||
}
|
||||
}
|
||||
<option value="local">@SharedLocalizer["LocalVersion"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (!string.IsNullOrEmpty(_location))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="location" HelpText="Location where the module will be created" ResourceKey="Location">Location: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="module" class="form-control" @bind="@_location" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
<button type="button" class="btn btn-success" @onclick="CreateModule">@Localizer["Module.Create"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick="ActivateModule">@Localizer["Module.Activate"]</button>
|
||||
}
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private string _moduledefinitionname = string.Empty;
|
||||
private string _owner = string.Empty;
|
||||
private string _module = string.Empty;
|
||||
private string _description = string.Empty;
|
||||
private List<Template> _templates;
|
||||
private string _template = "-";
|
||||
private string[] _versions;
|
||||
private string _reference = "local";
|
||||
private string _minversion = "2.0.0";
|
||||
private string _location = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_moduledefinitionname = SettingService.GetSetting(ModuleState.Settings, "ModuleDefinitionName", "");
|
||||
if (string.IsNullOrEmpty(_moduledefinitionname))
|
||||
{
|
||||
AddModuleMessage(Localizer["Info.Module.Creator"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Info.Module.Activate"], MessageType.Info);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_templates = await ModuleDefinitionService.GetModuleDefinitionTemplatesAsync();
|
||||
_versions = Constants.ReleaseVersions.Split(',').Where(item => Version.Parse(item).CompareTo(Version.Parse("2.0.0")) >= 0).ToArray();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Module Creator");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateModule()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
|
||||
{
|
||||
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference };
|
||||
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
||||
|
||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||
settings = SettingService.SetSetting(settings, "ModuleDefinitionName", moduleDefinition.ModuleDefinitionName);
|
||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||
|
||||
GetLocation();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Module.Create"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Require.ValidName"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Creating Module");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ActivateModule()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_moduledefinitionname))
|
||||
{
|
||||
Module module = await ModuleService.GetModuleAsync(ModuleState.ModuleId);
|
||||
module.ModuleDefinitionName = _moduledefinitionname;
|
||||
await ModuleService.UpdateModuleAsync(module);
|
||||
NavigationManager.NavigateTo(NavigateUrl(), true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Activating Module");
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsValid(string name)
|
||||
{
|
||||
// must contain letters, underscores and digits and first character must be letter or underscore
|
||||
return !string.IsNullOrEmpty(name) && name.ToLower() != "module" && !name.ToLower().Contains("oqtane") && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
||||
}
|
||||
|
||||
private void TemplateChanged(ChangeEventArgs e)
|
||||
{
|
||||
_template = (string)e.Value;
|
||||
_minversion = "2.0.0";
|
||||
if (_template != "-")
|
||||
{
|
||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||
_minversion = template.Version;
|
||||
}
|
||||
GetLocation();
|
||||
}
|
||||
|
||||
private void GetLocation()
|
||||
{
|
||||
_location = string.Empty;
|
||||
if (_owner != "" && _module != "" && _template != "-")
|
||||
{
|
||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||
_location = template.Location + _owner + "." + _module;
|
||||
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Modules.Admin.ModuleCreator
|
||||
{
|
||||
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
|
||||
public class ModuleInfo : IModule
|
||||
{
|
||||
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||
{
|
||||
Name = "Module Creator",
|
||||
Description = "Enables software developers to quickly create modules by automating many of the initial module creation tasks",
|
||||
Version = "1.0.0",
|
||||
Categories = "Developer"
|
||||
};
|
||||
}
|
||||
}
|
@ -8,67 +8,121 @@
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<TabStrip>
|
||||
<TabPanel Name="Download" ResourceKey="Download">
|
||||
<TabPanel Name="Download" ResourceKey="Download" Heading="Download">
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<select id="price" class="form-select custom-select" @onchange="(e => PriceChanged(e))">
|
||||
<option value="free">@SharedLocalizer["Free"]</option>
|
||||
<option value="paid">@SharedLocalizer["Paid"]</option>
|
||||
</select>
|
||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||
<div class="text-center">
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="free" class="form-check-input" type="radio" checked="@(_price == "free")" name="Price" @onchange="@(() => PriceChanged("free"))" />
|
||||
<label class="form-check-label" for="free">@SharedLocalizer["Free"]</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="paid" class="form-check-input" type="radio" checked="@(_price == "paid")" name="Price" @onchange="@(() => PriceChanged("paid"))" />
|
||||
<label class="form-check-label" for="paid">@SharedLocalizer["Paid"]</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (_packages != null)
|
||||
{
|
||||
if (_packages.Count > 0)
|
||||
{
|
||||
<Pager Items="@_packages">
|
||||
<Row>
|
||||
<td>
|
||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_new">@context.Name</a></h3> by: <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
||||
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
||||
@((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(context.PackageUrl).Host + "</strong>" : ""))
|
||||
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
||||
</td>
|
||||
<td style="width: 1px; vertical-align: middle;">
|
||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PackageUrl))
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
</td>
|
||||
<td style="width: 1px; vertical-align: middle;">
|
||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
||||
{
|
||||
<a class="btn btn-primary" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@context.Price.Value.ToString("$#,##0.00")</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
else
|
||||
{
|
||||
<br />
|
||||
<div class="mx-auto text-center">
|
||||
@Localizer["Search.NoResults"]
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">@Localizer["Product"]</span>
|
||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||
<button type="button" class="btn btn-primary ms-2" @onclick="Refresh"><span class="@Icons.Reload" aria-hidden="true"></span></button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col">
|
||||
@if (_initialized)
|
||||
{
|
||||
<br />
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-4">
|
||||
<h3>@((_packages != null) ? _packages.Count : 0) @SharedLocalizer["Search.Results"]</h3>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-select" value="@_sort" @onchange="(e => SortChanged(e))">
|
||||
<option value="popularity">@SharedLocalizer["Search.Popularity"]</option>
|
||||
<option value="alphabetical">@SharedLocalizer["Search.Alphabetical"]</option>
|
||||
@if (_price == "free")
|
||||
{
|
||||
<option value="downloads">@SharedLocalizer["Search.Downloads"]</option>
|
||||
}
|
||||
<option value="recent">@SharedLocalizer["Search.RecentlyReleased"]</option>
|
||||
@if (_price == "paid")
|
||||
{
|
||||
<option value="price">@SharedLocalizer["Search.Price"]</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<Pager Format="Grid" Items="@_packages" DisplayPages="1" PageSize="9" Toolbar="Both" Class="container-fluid px-0" RowClass="row g-0" ColumnClass="col-lg-4 col-md-6" CurrentPage="@_page.ToString()" OnPageChange="OnPageChange">
|
||||
<Row>
|
||||
<div class="m-2 p-2 d-flex justify-content-center">
|
||||
<div class="container-fluid px-0">
|
||||
<div class="row g-0 mb-2">
|
||||
<div class="col-4">
|
||||
<a href="@context.ProductUrl" target="_blank">
|
||||
@if (context.LogoUrl != null)
|
||||
{
|
||||
<img src="@context.LogoUrl" class="img-fluid" alt="@context.Name" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<img src="/package.png" class="img-fluid" alt="@context.Name" />
|
||||
}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-8 text-end">
|
||||
<small>@SharedLocalizer["Search.Version"]:</small> <strong>@context.Version</strong>
|
||||
<br /><small>@SharedLocalizer["Search.Released"]:</small> <strong>@context.ReleaseDate.ToString("MM/dd/yyyy")</strong>
|
||||
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||
{
|
||||
<br /><small>@SharedLocalizer["Search.Source"]:</small> <strong>@(new Uri(context.PackageUrl).Host)</strong>
|
||||
}
|
||||
@if (context.Price == null)
|
||||
{
|
||||
<br /><small>@SharedLocalizer["Search.Downloads"]:</small> <strong>@(String.Format("{0:n0}", context.Downloads))</strong>
|
||||
}
|
||||
else
|
||||
{
|
||||
<br /><small>@SharedLocalizer["From"]:</small> <strong>@context.Price.Value.ToString("$#,##0.00")</strong>
|
||||
@((MarkupString)(context.TrialPeriod > 0 ? " <strong>(" + context.TrialPeriod + " Day Trial)</strong>" : ""))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-0">
|
||||
<div class="col">
|
||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_blank">@context.Name</a></h3><br />
|
||||
<small>@SharedLocalizer["Search.By"]:</small> <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
||||
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
||||
<br />
|
||||
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
||||
{
|
||||
<a class="btn btn-success ms-2" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@SharedLocalizer["Buy"]</a>
|
||||
}
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
||||
</TabPanel>
|
||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
||||
<TabPanel Name="Upload" ResourceKey="Upload" Heading="Upload">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Module: </Label>
|
||||
@ -116,8 +170,11 @@
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private int _page = 1;
|
||||
private List<Package> _packages;
|
||||
private string _price = "free";
|
||||
private string _sort = "popularity";
|
||||
private string _search = "";
|
||||
private string _productname = "";
|
||||
private string _packageid = "";
|
||||
@ -131,6 +188,7 @@
|
||||
try
|
||||
{
|
||||
await LoadModuleDefinitions();
|
||||
_initialized = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -141,8 +199,10 @@
|
||||
|
||||
private async Task LoadModuleDefinitions()
|
||||
{
|
||||
ShowProgressIndicator();
|
||||
|
||||
var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||
_packages = await PackageService.GetPackagesAsync("module", _search, _price, "");
|
||||
_packages = await PackageService.GetPackagesAsync("module", _search, _price, "", _sort);
|
||||
|
||||
if (_packages != null)
|
||||
{
|
||||
@ -154,46 +214,44 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HideProgressIndicator();
|
||||
}
|
||||
|
||||
private async void PriceChanged(ChangeEventArgs e)
|
||||
private async void PriceChanged(string price)
|
||||
{
|
||||
try
|
||||
{
|
||||
_price = (string)e.Value;
|
||||
_search = "";
|
||||
await LoadModuleDefinitions();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On PriceChanged");
|
||||
}
|
||||
_price = price;
|
||||
_sort = "popularity";
|
||||
await LoadModuleDefinitions();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task Search()
|
||||
{
|
||||
try
|
||||
{
|
||||
await LoadModuleDefinitions();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On Search");
|
||||
}
|
||||
await LoadModuleDefinitions();
|
||||
}
|
||||
|
||||
private async Task Reset()
|
||||
{
|
||||
try
|
||||
{
|
||||
_search = "";
|
||||
await LoadModuleDefinitions();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On Reset");
|
||||
}
|
||||
_page = 1;
|
||||
_search = "";
|
||||
await LoadModuleDefinitions();
|
||||
}
|
||||
|
||||
private async Task Refresh()
|
||||
{
|
||||
await LoadModuleDefinitions();
|
||||
}
|
||||
|
||||
private void OnPageChange(int page)
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
private async void SortChanged(ChangeEventArgs e)
|
||||
{
|
||||
_sort = (string)e.Value;
|
||||
await LoadModuleDefinitions();
|
||||
}
|
||||
|
||||
private void HideModal()
|
||||
@ -207,7 +265,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
var package = await PackageService.GetPackageAsync(packageid, version);
|
||||
var package = await PackageService.GetPackageAsync(packageid, version, false);
|
||||
if (package != null)
|
||||
{
|
||||
_productname = package.Name;
|
||||
@ -217,8 +275,13 @@
|
||||
_packagelicense = package.License.Replace("\n", "<br />");
|
||||
}
|
||||
_packageversion = package.Version;
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError("Error Getting Package {PackageId} {Version}", packageid, version);
|
||||
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -231,7 +294,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_packageid, _packageversion, Constants.PackagesFolder);
|
||||
await PackageService.DownloadPackageAsync(_packageid, _packageversion);
|
||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _packageversion);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Module.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
_productname = "";
|
||||
|
@ -89,7 +89,10 @@
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
AddModuleMessage(Localizer["Info.Module.Development"], MessageType.Info);
|
||||
if (!NavigationManager.BaseUri.Contains("localhost:"))
|
||||
{
|
||||
AddModuleMessage(Localizer["Info.Module.Development"], MessageType.Info);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
@ -115,10 +118,18 @@
|
||||
{
|
||||
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
|
||||
{
|
||||
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference };
|
||||
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
||||
GetLocation();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Module.Create"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
if (IsValidXML(_description))
|
||||
{
|
||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference, ModuleDefinitionName = template.Namespace };
|
||||
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
||||
GetLocation();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Module.Create"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Require.ValidDescription"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -139,7 +150,13 @@
|
||||
private bool IsValid(string name)
|
||||
{
|
||||
// must contain letters, underscores and digits and first character must be letter or underscore
|
||||
return !string.IsNullOrEmpty(name) && name.ToLower() != "module" && !name.ToLower().Contains("oqtane") && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
||||
return !string.IsNullOrEmpty(name) && name.ToLower() != "module" && !name.ToLower().Contains("oqtane") && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
||||
}
|
||||
|
||||
private bool IsValidXML(string description)
|
||||
{
|
||||
// must contain letters, digits, or spaces
|
||||
return Regex.IsMatch(description, "^[A-Za-z0-9 .,!?]+$");
|
||||
}
|
||||
|
||||
private void TemplateChanged(ChangeEventArgs e)
|
||||
@ -151,7 +168,7 @@
|
||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||
_minversion = template.Version;
|
||||
}
|
||||
GetLocation();
|
||||
GetLocation();
|
||||
}
|
||||
|
||||
private void GetLocation()
|
||||
@ -160,8 +177,14 @@
|
||||
if (_owner != "" && _module != "" && _template != "-")
|
||||
{
|
||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||
_location = template.Location + _owner + "." + _module;
|
||||
|
||||
if (!string.IsNullOrEmpty(template.Namespace))
|
||||
{
|
||||
_location = template.Location + template.Namespace.Replace("[Owner]", _owner).Replace("[Module]", _module);
|
||||
}
|
||||
else
|
||||
{
|
||||
_location = template.Location + _owner + ".Module." + _module;
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
@if (_initialized)
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Definition" ResourceKey="Definition">
|
||||
<TabPanel Name="Definition" ResourceKey="Definition" Heading="Definition">
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -33,7 +33,16 @@
|
||||
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isenabled" HelpText="Is module enabled for this site?" ResourceKey="IsEnabled">Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isenabled" class="form-select" @bind="@_isenabled" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<Section Name="Information" ResourceKey="Information">
|
||||
<div class="container">
|
||||
@ -50,9 +59,26 @@
|
||||
</div>
|
||||
</div>
|
||||
<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" 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">
|
||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||
@if (!string.IsNullOrEmpty(_packagename))
|
||||
{
|
||||
<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 class="row mb-1 align-items-center">
|
||||
@ -76,13 +102,14 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="license" HelpText="The module license terms" ResourceKey="License">License: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="runtimes" HelpText="The Blazor runtimes which this module supports" ResourceKey="Runtimes">Runtimes: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="runtimes" class="form-control" @bind="@_runtimes" disabled />
|
||||
@if (_license.StartsWith("http") || _license.StartsWith("/") || _license.StartsWith("~"))
|
||||
{
|
||||
<a href="@_license.Replace("~", PageState?.Alias.BaseUrl + "/Modules/" + Utilities.GetTypeName(_moduledefinitionname))" class="btn btn-info" style="text-decoration: none !important" target="_new">@Localizer["View License"]</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -94,7 +121,7 @@
|
||||
<br />
|
||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
||||
<TabPanel Name="Permissions" ResourceKey="Permissions" Heading="Permissions">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<PermissionGrid EntityName="@EntityNames.ModuleDefinition" PermissionNames="@PermissionNames.Utilize" PermissionList="@_permissions" @ref="_permissionGrid" />
|
||||
@ -104,7 +131,7 @@
|
||||
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Translations" ResourceKey="Translations">
|
||||
<TabPanel Name="Translations" ResourceKey="Translations" Heading="Translations">
|
||||
@if (_languages != null && _languages.Count > 0)
|
||||
{
|
||||
<Pager Items="@_languages">
|
||||
@ -181,7 +208,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
|
||||
<button type="button" class="btn btn-success" @onclick="DownloadTranslation">@SharedLocalizer["Accept"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -199,14 +226,15 @@
|
||||
private string _name;
|
||||
private string _description = "";
|
||||
private string _categories;
|
||||
private string _isenabled;
|
||||
private string _moduledefinitionname = "";
|
||||
private string _version;
|
||||
private string _packagename = "";
|
||||
private string _packageurl = "";
|
||||
private string _owner = "";
|
||||
private string _url = "";
|
||||
private string _contact = "";
|
||||
private string _license = "";
|
||||
private string _runtimes = "";
|
||||
private List<Permission> _permissions = null;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
@ -234,6 +262,7 @@
|
||||
_name = moduleDefinition.Name;
|
||||
_description = moduleDefinition.Description;
|
||||
_categories = moduleDefinition.Categories;
|
||||
_isenabled = moduleDefinition.IsEnabled.ToString();
|
||||
_moduledefinitionname = moduleDefinition.ModuleDefinitionName;
|
||||
_version = moduleDefinition.Version;
|
||||
_packagename = moduleDefinition.PackageName;
|
||||
@ -241,7 +270,6 @@
|
||||
_url = moduleDefinition.Url;
|
||||
_contact = moduleDefinition.Contact;
|
||||
_license = moduleDefinition.License;
|
||||
_runtimes = moduleDefinition.Runtimes;
|
||||
_permissions = moduleDefinition.PermissionList;
|
||||
_createdby = moduleDefinition.CreatedBy;
|
||||
_createdon = moduleDefinition.CreatedOn;
|
||||
@ -297,6 +325,7 @@
|
||||
{
|
||||
moduledefinition.Categories = _categories;
|
||||
}
|
||||
moduledefinition.IsEnabled = (_isenabled == null ? true : bool.Parse(_isenabled));
|
||||
moduledefinition.PermissionList = _permissionGrid.GetPermissionList();
|
||||
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
|
||||
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);
|
||||
@ -307,76 +336,108 @@
|
||||
AddModuleMessage(Localizer["Message.DuplicateName"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving ModuleDefinition {ModuleDefinitionId} {Error}", _moduleDefinitionId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Save"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving ModuleDefinition {ModuleDefinitionId} {Error}", _moduleDefinitionId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Save"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private void HideModal()
|
||||
{
|
||||
_package = null;
|
||||
StateHasChanged();
|
||||
}
|
||||
private void HideModal()
|
||||
{
|
||||
_package = null;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private string TranslationAvailable(string packagename, string version)
|
||||
{
|
||||
if (_packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||
if (package != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(version))
|
||||
{
|
||||
return "install";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
||||
{
|
||||
return "upgrade";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
private string TranslationAvailable(string packagename, string version)
|
||||
{
|
||||
if (_packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||
if (package != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(version))
|
||||
{
|
||||
return "install";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
||||
{
|
||||
return "upgrade";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private async Task GetPackage(string packagename)
|
||||
{
|
||||
var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
|
||||
try
|
||||
{
|
||||
_package = await PackageService.GetPackageAsync(packagename, version);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packagename, version);
|
||||
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async Task GetPackage(string packagename)
|
||||
{
|
||||
var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
|
||||
try
|
||||
{
|
||||
_package = await PackageService.GetPackageAsync(packagename, version, false);
|
||||
if (_package != null)
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError("Error Getting Package {PackageId} {Version}", packagename, version);
|
||||
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packagename, version);
|
||||
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DownloadTranslation()
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version);
|
||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Translation.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
_package = null;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packagename, _version);
|
||||
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
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 async Task DownloadPackage()
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Translation.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
_package = null;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packagename, _version);
|
||||
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,13 +37,15 @@ else
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Pager Items="@_moduleDefinitions.Where(item => item.Categories.Contains(_category))">
|
||||
<Pager Items="@_moduleDefinitions">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@SharedLocalizer["Version"]</th>
|
||||
<th>@Localizer["Enabled"]</th>
|
||||
<th>@Localizer["InUse"]</th>
|
||||
<th>@SharedLocalizer["Support"]</th>
|
||||
<th>@SharedLocalizer["Expires"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
</Header>
|
||||
@ -57,6 +59,16 @@ else
|
||||
</td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Version</td>
|
||||
<td>
|
||||
@if (context.IsEnabled)
|
||||
{
|
||||
<span>@SharedLocalizer["Yes"]</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@SharedLocalizer["No"]</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (context.AssemblyName == Constants.ClientId || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
|
||||
{
|
||||
@ -67,6 +79,9 @@ else
|
||||
<span>@SharedLocalizer["No"]</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@((MarkupString)SupportLink(context.PackageName, context.Version))
|
||||
</td>
|
||||
<td>
|
||||
@((MarkupString)PurchaseLink(context.PackageName))
|
||||
</td>
|
||||
@ -84,52 +99,76 @@ else
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<ModuleDefinition> _moduleDefinitions;
|
||||
private List<Package> _packages;
|
||||
private List<string> _categories = new List<string>();
|
||||
private string _category = "Common";
|
||||
private List<ModuleDefinition> _allModuleDefinitions;
|
||||
private List<ModuleDefinition> _moduleDefinitions;
|
||||
private List<Package> _packages;
|
||||
private List<string> _categories = new List<string>();
|
||||
private string _category = "Common";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_moduleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||
_packages = await PackageService.GetPackagesAsync("module");
|
||||
_categories = _moduleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (_moduleDefinitions == null)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Modules {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
||||
await LoadModuleDefinitions();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (_moduleDefinitions == null)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Modules {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string PurchaseLink(string packagename)
|
||||
{
|
||||
string link = "";
|
||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||
if (package != null)
|
||||
{
|
||||
if (package.ExpiryDate != null && package.ExpiryDate.Value.Date != DateTime.MaxValue.Date)
|
||||
{
|
||||
link += "<span>" + package.ExpiryDate.Value.Date.ToString("MMM dd, yyyy") + "</span>";
|
||||
if (!string.IsNullOrEmpty(package.PaymentUrl))
|
||||
{
|
||||
link += " <a class=\"btn btn-primary\" style=\"text-decoration: none !important\" href=\"" + package.PaymentUrl + "\" target=\"_new\">" + SharedLocalizer["Extend"] + "</a>";
|
||||
}
|
||||
}
|
||||
private async Task LoadModuleDefinitions()
|
||||
{
|
||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
|
||||
_packages = await PackageService.GetPackageUpdatesAsync("module");
|
||||
}
|
||||
|
||||
private string PurchaseLink(string packagename)
|
||||
{
|
||||
string link = "";
|
||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||
if (package != null)
|
||||
{
|
||||
if (package.ExpiryDate != null && package.ExpiryDate.Value.Date != DateTime.MaxValue.Date)
|
||||
{
|
||||
if (string.IsNullOrEmpty(package.PaymentUrl))
|
||||
{
|
||||
link = "<span>" + package.ExpiryDate.Value.Date.ToString("MMM dd, yyyy") + "</span>";
|
||||
}
|
||||
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>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
private string SupportLink(string packagename, string version)
|
||||
{
|
||||
string link = "";
|
||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||
if (package != null && !string.IsNullOrEmpty(package.SupportUrl))
|
||||
{
|
||||
link += "<a class=\"btn btn-info\" style=\"text-decoration: none !important\" href=\"" + package.SupportUrl.Replace("{Version}", version) + "\" target=\"_new\">" + SharedLocalizer["Help"] + "</a>";
|
||||
}
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
private string UpgradeAvailable(string packagename, string version)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||
@ -147,7 +186,7 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
||||
await PackageService.DownloadPackageAsync(packagename, version);
|
||||
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
}
|
||||
@ -173,9 +212,9 @@ else
|
||||
}
|
||||
}
|
||||
|
||||
private void CategoryChanged(ChangeEventArgs e)
|
||||
private async Task CategoryChanged(ChangeEventArgs e)
|
||||
{
|
||||
_category = (string)e.Value;
|
||||
StateHasChanged();
|
||||
await LoadModuleDefinitions();
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
public override string Title => "Export Content";
|
||||
|
||||
|
||||
private async Task ExportModule()
|
||||
{
|
||||
try
|
||||
|
@ -14,10 +14,27 @@
|
||||
@if (_containers != null)
|
||||
{
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="module" HelpText="The name of the module" ResourceKey="Module">Module: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="module" type="text" class="form-control" @bind="@_module" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="title" HelpText="Enter the title of the module" ResourceKey="Title">Title: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="title" type="text" name="Title" class="form-control" @bind="@_title" required />
|
||||
<input id="title" type="text" class="form-control" @bind="@_title" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="pane" HelpText="The pane where the module will be displayed" ResourceKey="Pane">Pane: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-select" @bind="@_pane">
|
||||
@foreach (string pane in PageState.Page.Panes)
|
||||
{
|
||||
<option value="@pane">@pane Pane</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -44,12 +61,20 @@
|
||||
<Label Class="col-sm-3" For="page" HelpText="The page that the module is located on" ResourceKey="Page">Page: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="page" class="form-select" @bind="@_pageId" required>
|
||||
@foreach (Page p in PageState.Pages)
|
||||
@if (PageState.Page.UserId != null)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
<option value="@PageState.Page.PageId">@(PageState.Page.Name)</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Page p in PageState.Pages)
|
||||
{
|
||||
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList))
|
||||
{
|
||||
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
@ -90,110 +115,113 @@
|
||||
</form>
|
||||
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
public override string Title => "Module Settings";
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
public override string Title => "Module Settings";
|
||||
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private List<Theme> _themes;
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _title;
|
||||
private string _containerType;
|
||||
private string _allPages = "false";
|
||||
private string _permissionNames = "";
|
||||
private List<Permission> _permissions = null;
|
||||
private string _pageId;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _moduleSettingsType;
|
||||
private object _moduleSettings;
|
||||
private string _moduleSettingsTitle = "Module Settings";
|
||||
private RenderFragment ModuleSettingsComponent { get; set; }
|
||||
private Type _containerSettingsType;
|
||||
private object _containerSettings;
|
||||
private RenderFragment ContainerSettingsComponent { get; set; }
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _module;
|
||||
private string _title;
|
||||
private string _pane;
|
||||
private string _containerType;
|
||||
private string _allPages = "false";
|
||||
private string _permissionNames = "";
|
||||
private List<Permission> _permissions = null;
|
||||
private string _pageId;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _moduleSettingsType;
|
||||
private object _moduleSettings;
|
||||
private string _moduleSettingsTitle = "Module Settings";
|
||||
private RenderFragment ModuleSettingsComponent { get; set; }
|
||||
private Type _containerSettingsType;
|
||||
private object _containerSettings;
|
||||
private RenderFragment ContainerSettingsComponent { get; set; }
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_title = ModuleState.Title;
|
||||
_themes = await ThemeService.GetThemesAsync();
|
||||
_containers = ThemeService.GetContainerControls(_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;
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_module = ModuleState.ModuleDefinition.Name;
|
||||
_title = ModuleState.Title;
|
||||
_pane = ModuleState.Pane;
|
||||
_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;
|
||||
|
||||
if (ModuleState.ModuleDefinition != null)
|
||||
{
|
||||
_permissionNames = ModuleState.ModuleDefinition?.PermissionNames;
|
||||
if (ModuleState.ModuleDefinition != null)
|
||||
{
|
||||
_permissionNames = ModuleState.ModuleDefinition?.PermissionNames;
|
||||
|
||||
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
|
||||
{
|
||||
// module settings type explicitly declared in IModule interface
|
||||
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
if (_moduleSettingsType != null)
|
||||
{
|
||||
var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl;
|
||||
if (!string.IsNullOrEmpty(moduleobject.Title))
|
||||
{
|
||||
_moduleSettingsTitle = moduleobject.Title;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
|
||||
{
|
||||
// module settings type explicitly declared in IModule interface
|
||||
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
if (_moduleSettingsType != null)
|
||||
{
|
||||
var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl;
|
||||
if (!string.IsNullOrEmpty(moduleobject.Title))
|
||||
{
|
||||
_moduleSettingsTitle = moduleobject.Title;
|
||||
}
|
||||
|
||||
ModuleSettingsComponent = builder =>
|
||||
{
|
||||
builder.OpenComponent(0, _moduleSettingsType);
|
||||
builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); });
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error);
|
||||
}
|
||||
ModuleSettingsComponent = builder =>
|
||||
{
|
||||
builder.OpenComponent(0, _moduleSettingsType);
|
||||
builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); });
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error);
|
||||
}
|
||||
|
||||
var theme = _themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
||||
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
|
||||
{
|
||||
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
|
||||
if (_containerSettingsType != null)
|
||||
{
|
||||
ContainerSettingsComponent = builder =>
|
||||
{
|
||||
builder.OpenComponent(0, _containerSettingsType);
|
||||
builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); });
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
||||
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
|
||||
{
|
||||
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
|
||||
if (_containerSettingsType != null)
|
||||
{
|
||||
ContainerSettingsComponent = builder =>
|
||||
{
|
||||
builder.OpenComponent(0, _containerSettingsType);
|
||||
builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); });
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveModule()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_title))
|
||||
{
|
||||
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
||||
pagemodule.PageId = int.Parse(_pageId);
|
||||
pagemodule.Title = _title;
|
||||
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
|
||||
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
|
||||
private async Task SaveModule()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_title))
|
||||
{
|
||||
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
||||
pagemodule.PageId = int.Parse(_pageId);
|
||||
pagemodule.Title = _title;
|
||||
pagemodule.Pane = _pane;
|
||||
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
|
||||
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
|
||||
{
|
||||
pagemodule.ContainerType = string.Empty;
|
||||
}
|
||||
|
@ -3,15 +3,15 @@
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IPageService PageService
|
||||
@inject IThemeService ThemeService
|
||||
@inject ISystemService SystemService
|
||||
@inject IStringLocalizer<Add> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<TabStrip Refresh="@_refresh">
|
||||
<TabPanel Name="Settings" ResourceKey="Settings">
|
||||
@if (_themeList != null)
|
||||
{
|
||||
@if (_initialized)
|
||||
{
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<TabStrip Refresh="@_refresh">
|
||||
<TabPanel Name="Settings" ResourceKey="Settings" Heading="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
|
||||
@ -19,42 +19,67 @@
|
||||
<input id="name" class="form-control" @bind="@_name" required />
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<select id="parent" class="form-select" @onchange="(e => ParentChanged(e))" required>
|
||||
<option value="-1"><@Localizer["SiteRoot"]></option>
|
||||
@foreach (Page page in PageState.Pages)
|
||||
{
|
||||
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages" ResourceKey="Insert">Insert: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="insert" class="form-select" @bind="@_insert" required>
|
||||
<option value="<<">@Localizer["AtBeginning"]</option>
|
||||
@if (_children != null && _children.Count > 0)
|
||||
{
|
||||
<option value="<">@Localizer["Before"]</option>
|
||||
<option value=">">@Localizer["After"]</option>
|
||||
}
|
||||
<option value=">>">@Localizer["AtEnd"]</option>
|
||||
</select>
|
||||
@if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">"))
|
||||
{
|
||||
<select class="form-select" @bind="@_childid">
|
||||
<option value="-1"><@Localizer["Page.Select"]></option>
|
||||
@foreach (Page page in _children)
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
|
||||
<option value="-1"><@Localizer["SiteRoot"]></option>
|
||||
@foreach (Page page in PageState.Pages)
|
||||
{
|
||||
<option value="@(page.PageId)">@(page.Name)</option>
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
|
||||
{
|
||||
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages" ResourceKey="Insert">Insert: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="insert" class="form-select" @bind="@_insert" required>
|
||||
@if (_children != null && _children.Count > 0)
|
||||
{
|
||||
<option value="<<">@Localizer["AtBeginning"]</option>
|
||||
<option value="<">@Localizer["Before"]</option>
|
||||
<option value=">">@Localizer["After"]</option>
|
||||
}
|
||||
<option value=">>">@Localizer["AtEnd"]</option>
|
||||
</select>
|
||||
@if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">"))
|
||||
{
|
||||
<select class="form-select" @bind="@_childid">
|
||||
<option value="-1"><@Localizer["Page.Select"]></option>
|
||||
@foreach (Page page in _children)
|
||||
{
|
||||
<option value="@(page.PageId)">@(page.Name)</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<select id="parent" class="form-select" @onchange="(e => ParentChanged(e))" required>
|
||||
<option value="@(_parent.PageId)">@(new string('-', _parent.Level * 2))@(_parent.Name)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages" ResourceKey="Insert">Insert: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="insert" class="form-select" @bind="@_insert" required>
|
||||
<option value=">>">@Localizer["AtEnd"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="navigation" HelpText="Select whether the page is part of the site navigation or hidden" ResourceKey="Navigation">Navigation? </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -85,9 +110,27 @@
|
||||
<input id="url" class="form-control" @bind="@_url" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="icon" HelpText="Optionally provide an icon class name for this page which will be displayed in the site navigation" ResourceKey="Icon">Icon: </Label>
|
||||
<div class="col-sm-8">
|
||||
<InputList Value="@_icon" ValueChanged="IconChanged" DataList="@_icons" ResourceKey="Icon" ResourceType="@_iconresources" />
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<i class="@_icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content" ResourceKey="Personalizable">Personalizable? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="personalizable" class="form-select" @bind="@_ispersonalizable" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Section Name="Appearance" ResourceKey="Appearance">
|
||||
<Section Name="Appearance" ResourceKey="Appearance" Heading=@Localizer["Appearance.Name"]>
|
||||
<div class="container">
|
||||
<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>
|
||||
@ -95,12 +138,6 @@
|
||||
<input id="title" class="form-control" @bind="@_title" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="meta" HelpText="Optionally enter meta tags (in exactly the form you want them to be included in the page output)." ResourceKey="Meta">Meta: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="meta" class="form-control" @bind="@_meta" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
@ -116,7 +153,6 @@
|
||||
<Label Class="col-sm-3" For="container" HelpText="Select the default container for the page" ResourceKey="DefaultContainer">Default Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="container" class="form-select" @bind="@_containertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
@ -124,90 +160,124 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="PageContent" ResourceKey="PageContent" Heading=@Localizer["PageContent.Heading"]>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="icon" HelpText="Optionally provide an icon class name for this page which will be displayed in the site navigation" ResourceKey="Icon">Icon: </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">
|
||||
<input id="icon" class="form-control" @bind="@_icon" />
|
||||
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content" ResourceKey="Personalizable">Personalizable? </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">
|
||||
<select id="personalizable" class="form-select" @bind="@_ispersonalizable" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
|
||||
</div>
|
||||
</div>
|
||||
</TabPanel>
|
||||
@if (_themeSettingsType != null)
|
||||
{
|
||||
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
|
||||
@ThemeSettingsComponent
|
||||
</TabPanel>
|
||||
}
|
||||
</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>
|
||||
<TabPanel Name="Permissions" ResourceKey="Permissions" Heading=@Localizer["Permissions.Heading"]>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
|
||||
</div>
|
||||
</div>
|
||||
</TabPanel>
|
||||
@if (_themeSettingsType != null)
|
||||
{
|
||||
<TabPanel Name="ThemeSettings" Heading=@Localizer["Theme.Heading"] ResourceKey="ThemeSettings">
|
||||
@ThemeSettingsComponent
|
||||
</TabPanel>
|
||||
}
|
||||
</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>
|
||||
}
|
||||
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name;
|
||||
private string _title;
|
||||
private string _meta;
|
||||
private string _path = string.Empty;
|
||||
private string _parentid = "-1";
|
||||
private string _insert = ">>";
|
||||
private List<Page> _children;
|
||||
private int _childid = -1;
|
||||
private string _isnavigation = "True";
|
||||
private string _isclickable = "True";
|
||||
private string _url;
|
||||
private string _ispersonalizable = "False";
|
||||
private string _themetype = string.Empty;
|
||||
private string _containertype = string.Empty;
|
||||
private string _icon = string.Empty;
|
||||
private string _permissions = null;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _themeSettingsType;
|
||||
private object _themeSettings;
|
||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private bool _initialized = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private int _pageId;
|
||||
private string _name;
|
||||
private string _parentid = "-1";
|
||||
private string _insert = ">>";
|
||||
private List<Page> _children;
|
||||
private int _childid = -1;
|
||||
private string _isnavigation = "True";
|
||||
private string _isclickable = "True";
|
||||
private string _path = string.Empty;
|
||||
private string _url;
|
||||
private string _ispersonalizable = "False";
|
||||
private string _title;
|
||||
private string _icon = string.Empty;
|
||||
private string _themetype = string.Empty;
|
||||
private string _containertype = string.Empty;
|
||||
private string _headcontent;
|
||||
private string _bodycontent;
|
||||
private string _permissions = null;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _themeSettingsType;
|
||||
private object _themeSettings;
|
||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
protected Page _parent = null;
|
||||
protected Dictionary<string, string> _icons;
|
||||
private string _iconresources = "";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
_themetype = PageState.Site.DefaultThemeType;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = PageState.Site.DefaultContainerType;
|
||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||
ThemeSettings();
|
||||
}
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("id"))
|
||||
{
|
||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||
_parent = await PageService.GetPageAsync(_pageId);
|
||||
if (_parent != null)
|
||||
{
|
||||
_parentid = _parent.PageId.ToString();
|
||||
}
|
||||
}
|
||||
_icons = await SystemService.GetIconsAsync();
|
||||
_iconresources = typeof(IconResources).FullName;
|
||||
|
||||
// if admin or user has edit access to parent page
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin) || (_parent != null && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, _parent.PermissionList)))
|
||||
{
|
||||
_themetype = PageState.Site.DefaultThemeType;
|
||||
_themes = ThemeService.GetThemeControls(PageState.Site.Themes);
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||
_containertype = PageState.Site.DefaultContainerType;
|
||||
_children = new List<Page>();
|
||||
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
ThemeSettings();
|
||||
_initialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogWarning("Error Loading Page {ParentId}", _parentid);
|
||||
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Page.Initialize"], MessageType.Error);
|
||||
await logger.LogError(ex, "Error Loading Page {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,28 +286,15 @@
|
||||
try
|
||||
{
|
||||
_parentid = (string)e.Value;
|
||||
_children = new List<Page>();
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
_children = new List<Page>();
|
||||
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -246,27 +303,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = "-";
|
||||
ThemeSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
if (ThemeService.GetTheme(PageState.Site.Themes, _themetype)?.ThemeName != ThemeService.GetTheme(PageState.Site.Themes, PageState.Site.DefaultThemeType)?.ThemeName)
|
||||
{
|
||||
AddModuleMessage(Localizer["ThemeChanged.Message"], MessageType.Warning);
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||
_containertype = _containers.First().TypeName;
|
||||
ThemeSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void ThemeSettings()
|
||||
{
|
||||
_themeSettingsType = null;
|
||||
var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
|
||||
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
|
||||
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
|
||||
{
|
||||
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
|
||||
@ -292,12 +345,11 @@
|
||||
Page page = null;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||
if (!string.IsNullOrEmpty(_themetype) && !string.IsNullOrEmpty(_containertype))
|
||||
{
|
||||
page = new Page();
|
||||
page.SiteId = PageState.Page.SiteId;
|
||||
page.Name = _name;
|
||||
page.Title = _title;
|
||||
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
@ -365,34 +417,42 @@
|
||||
|
||||
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
|
||||
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
||||
page.Url = _url;
|
||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||
page.Url = _url;
|
||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
|
||||
// appearance
|
||||
page.Title = _title;
|
||||
page.Icon = (_icon == null ? string.Empty : _icon);
|
||||
page.ThemeType = _themetype;
|
||||
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||
{
|
||||
page.ThemeType = string.Empty;
|
||||
}
|
||||
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||
page.DefaultContainerType = _containertype;
|
||||
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
page.DefaultContainerType = string.Empty;
|
||||
}
|
||||
page.Icon = (_icon == null ? string.Empty : _icon);
|
||||
|
||||
// page content
|
||||
page.HeadContent = _headcontent;
|
||||
page.BodyContent = _bodycontent;
|
||||
|
||||
// permissions
|
||||
page.PermissionList = _permissionGrid.GetPermissionList();
|
||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
page.Meta = _meta;
|
||||
|
||||
page = await PageService.AddPageAsync(page);
|
||||
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
||||
|
||||
await logger.LogInformation("Page Added {Page}", page);
|
||||
if (PageState.QueryString.ContainsKey("cp"))
|
||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Pages.First(item => item.PageId == int.Parse(PageState.QueryString["cp"])).Path));
|
||||
NavigationManager.NavigateTo(page.Path); // redirect to new page
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(page.Path));
|
||||
NavigationManager.NavigateTo(NavigateUrl()); // redirect to page management
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -415,13 +475,17 @@
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("cp"))
|
||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Pages.First(item => item.PageId == int.Parse(PageState.QueryString["cp"])).Path));
|
||||
NavigationManager.NavigateTo(PageState.ReturnUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
}
|
||||
private void IconChanged(string NewIcon)
|
||||
{
|
||||
_icon = NewIcon;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,11 +5,11 @@
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (PageState.Pages != null)
|
||||
@if (PageState.Pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
<ActionLink Action="Add" Text="Add Page" ResourceKey="AddPage" />
|
||||
|
||||
<Pager Items="@PageState.Pages.Where(item => !item.IsDeleted)">
|
||||
<Pager Items="@PageState.Pages.Where(item => !item.IsDeleted)" SearchProperties="Name">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="description" HelpText="The help text displayed to the user for this profile item" ResourceKey="Description">Description: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="description" class="form-control" @bind="@_description" rows="5" maxlength="256" required ></textarea>
|
||||
<textarea id="description" class="form-control" @bind="@_description" rows="3" maxlength="256" required ></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -43,6 +43,12 @@
|
||||
<input id="length" class="form-control" @bind="@_maxlength" maxlength="4" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="rows" HelpText="The number of rows for text entry (one is the default)" ResourceKey="Rows">Rows: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="rows" class="form-control" @bind="@_rows" maxlength="2" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultVal" HelpText="The default value for this profile item" ResourceKey="DefaultValue">Default Value: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -64,6 +70,12 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="validation" HelpText="Optionally provide a regular expression (RegExp) for validating the value entered" ResourceKey="Validation">Validation: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="validation" class="form-control" @bind="@_validation" maxlength="200" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="private" HelpText="Should this profile item be visible to all users?" ResourceKey="Private">Private? </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -95,8 +107,10 @@
|
||||
private string _category = string.Empty;
|
||||
private string _vieworder = "0";
|
||||
private string _maxlength = "0";
|
||||
private string _rows = "1";
|
||||
private string _defaultvalue = string.Empty;
|
||||
private string _options = string.Empty;
|
||||
private string _validation = string.Empty;
|
||||
private string _isrequired = "False";
|
||||
private string _isprivate = "False";
|
||||
private string createdby;
|
||||
@ -124,8 +138,10 @@
|
||||
_category = profile.Category;
|
||||
_vieworder = profile.ViewOrder.ToString();
|
||||
_maxlength = profile.MaxLength.ToString();
|
||||
_rows = profile.Rows.ToString();
|
||||
_defaultvalue = profile.DefaultValue;
|
||||
_options = profile.Options;
|
||||
_validation = profile.Validation;
|
||||
_isrequired = profile.IsRequired.ToString();
|
||||
_isprivate = profile.IsPrivate.ToString();
|
||||
createdby = profile.CreatedBy;
|
||||
@ -167,8 +183,10 @@
|
||||
profile.Category = _category;
|
||||
profile.ViewOrder = int.Parse(_vieworder);
|
||||
profile.MaxLength = int.Parse(_maxlength);
|
||||
profile.Rows = int.Parse(_rows);
|
||||
profile.DefaultValue = _defaultvalue;
|
||||
profile.Options = _options;
|
||||
profile.Validation = _validation;
|
||||
profile.IsRequired = (_isrequired == null ? false : Boolean.Parse(_isrequired));
|
||||
profile.IsPrivate = (_isprivate == null ? false : Boolean.Parse(_isprivate));
|
||||
if (_profileid != -1)
|
||||
|
@ -12,16 +12,22 @@ else
|
||||
{
|
||||
<ActionLink Action="Add" Text="Add Profile" Security="SecurityAccessLevel.Edit" ResourceKey="AddProfile" />
|
||||
|
||||
<Pager Items="@_profiles">
|
||||
<Pager Items="@_profiles" SearchProperties="Title,Category">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@Localizer["Title"]</th>
|
||||
<th>@Localizer["Category"]</th>
|
||||
<th>@Localizer["Order"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
|
||||
<td><ActionDialog Header="Delete Profile" Message="@string.Format(Localizer["Confirm.Profile.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Title</td>
|
||||
<td>@context.Category</td>
|
||||
<td>@context.ViewOrder</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Pages" ResourceKey="Pages">
|
||||
<TabPanel Name="Pages" ResourceKey="Pages" Heading="Pages">
|
||||
@if (!_pages.Where(item => item.IsDeleted).Any())
|
||||
{
|
||||
<br />
|
||||
@ -31,7 +31,7 @@ else
|
||||
<th>@Localizer["DeletedOn"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-success" title="Restore">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>@context.Name</td>
|
||||
<td>@context.DeletedBy</td>
|
||||
@ -42,7 +42,7 @@ else
|
||||
<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 Name="Modules" ResourceKey="Modules">
|
||||
<TabPanel Name="Modules" ResourceKey="Modules" Heading="Modules">
|
||||
@if (!_modules.Where(item => item.IsDeleted).Any())
|
||||
{
|
||||
<br />
|
||||
@ -76,8 +76,8 @@ else
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<Page> _pages;
|
||||
private List<Module> _modules;
|
||||
private List<Page> _pages;
|
||||
private List<Module> _modules;
|
||||
private int _pagePage = 1;
|
||||
private int _pageModule = 1;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
@ -184,13 +184,6 @@ else
|
||||
try
|
||||
{
|
||||
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
||||
|
||||
// check if there are any remaining module instances in the site
|
||||
if (!_modules.Exists (item => item.ModuleId == module.ModuleId && item.PageModuleId != module.PageModuleId))
|
||||
{
|
||||
await ModuleService.DeleteModuleAsync(module.ModuleId);
|
||||
}
|
||||
|
||||
await logger.LogInformation("Module Permanently Deleted {Module}", module);
|
||||
await Load();
|
||||
StateHasChanged();
|
||||
@ -210,16 +203,7 @@ else
|
||||
foreach (Module module in _modules.Where(item => item.IsDeleted).ToList())
|
||||
{
|
||||
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
||||
|
||||
// DeletePageModuleAsync does not update _modules so remove it.
|
||||
_modules.Remove(module);
|
||||
// check if there are any remaining module instances in the site
|
||||
if (!_modules.Exists(item => item.ModuleId == module.ModuleId && item.PageModuleId != module.PageModuleId))
|
||||
{
|
||||
await ModuleService.DeleteModuleAsync(module.ModuleId);
|
||||
}
|
||||
}
|
||||
|
||||
await logger.LogInformation("Modules Permanently Deleted");
|
||||
await Load();
|
||||
ModuleInstance.HideProgressIndicator();
|
||||
|
@ -16,7 +16,7 @@
|
||||
<ModuleMessage Message="@Localizer["Info.Registration.Exists"]" Type="MessageType.Info" />
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<ModuleMessage Message="@_passwordconstruction" Type="MessageType.Info" />
|
||||
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -69,6 +69,7 @@ else
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _passwordrequirements;
|
||||
private string _username = string.Empty;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
@ -79,44 +80,16 @@ else
|
||||
private string _email = string.Empty;
|
||||
private string _displayname = string.Empty;
|
||||
|
||||
//Password construction
|
||||
private string _minimumlength;
|
||||
private string _uniquecharacters;
|
||||
private bool _requiredigit;
|
||||
private bool _requireupper;
|
||||
private bool _requirelower;
|
||||
private bool _requirepunctuation;
|
||||
private string _passwordconstruction;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
|
||||
_minimumlength = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredLength", "6");
|
||||
_uniquecharacters = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", "1");
|
||||
_requiredigit = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireDigit", "true"));
|
||||
_requireupper = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireUppercase", "true"));
|
||||
_requirelower = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireLowercase", "true"));
|
||||
_requirepunctuation = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireNonAlphanumeric", "true"));
|
||||
|
||||
// Replace the placeholders with the actual values of the variables
|
||||
string digitRequirement = _requiredigit ? Localizer["Password.DigitRequirement"] + ", " : "";
|
||||
string uppercaseRequirement = _requireupper ? Localizer["Password.UppercaseRequirement"] + ", " : "";
|
||||
string lowercaseRequirement = _requirelower ? Localizer["Password.LowercaseRequirement"] + ", " : "";
|
||||
string punctuationRequirement = _requirepunctuation ? Localizer["Password.PunctuationRequirement"] + ", " : "";
|
||||
|
||||
// Replace the placeholders with the actual values of the variables
|
||||
string passwordValidationCriteriaTemplate = Localizer["Password.ValidationCriteria"];
|
||||
_passwordconstruction = Localizer["Info.Registration.InvalidEmail"] + ". " + string.Format(passwordValidationCriteriaTemplate,
|
||||
_minimumlength, _uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
|
||||
private async Task Register()
|
||||
|
@ -6,6 +6,7 @@
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="username" HelpText="Your username will be populated from the link you received in the password reset notification" ResourceKey="Username">Username: </Label>
|
||||
@ -45,12 +46,14 @@
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string _confirm = string.Empty;
|
||||
private string _passwordrequirements;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||
|
||||
if (PageState.QueryString.ContainsKey("name") && PageState.QueryString.ContainsKey("token"))
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ else
|
||||
{
|
||||
<ActionLink Action="Add" Text="Add Role" Security="SecurityAccessLevel.Edit" ResourceKey="AddRole" />
|
||||
|
||||
<Pager Items="@_roles">
|
||||
<Pager Items="@_roles" SearchProperties="Name">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
|
@ -22,60 +22,11 @@
|
||||
<input id="name" class="form-control" @bind="@_name" maxlength="200" required />
|
||||
</div>
|
||||
</div>
|
||||
<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="@Constants.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" @ref="_faviconfilemanager" />
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
|
||||
<option value="-"><@Localizer["Theme.Select"]></option>
|
||||
@foreach (var theme in _themes)
|
||||
{
|
||||
<option value="@theme.TypeName">@theme.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultContainer" class="form-select" @bind="@_containertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultAdminContainer" class="form-select" @bind="@_admincontainertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
<option value="@Constants.DefaultAdminContainer"><@Localizer["DefaultAdminContainer"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="homepage" HelpText="Select the home page for the site (to be used if there is no page with a path of '/')" ResourceKey="HomePage">Home Page: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="homepage" class="form-select" @bind="@_homepageid" required>
|
||||
<option value="-"><@Localizer["Not Specified"]></option>
|
||||
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
||||
@foreach (Page page in PageState.Pages)
|
||||
{
|
||||
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||
@ -98,10 +49,92 @@
|
||||
<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" ResourceKey="SiteMap">Site Map: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="sitemap" class="form-control" @bind="@_sitemap" required disabled />
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input id="sitemap" class="form-control" @bind="@_sitemap" disabled />
|
||||
<a href="@_sitemap" class="btn btn-secondary" target="_new">@Localizer["Browse"]</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<input id="siteguid" class="form-control" @bind="@_siteguid" required disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="version" HelpText="The site version (for site content migrations)" ResourceKey="Version">Version: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="version" class="form-control" @bind="@_version" required disabled />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<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="@Constants.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">
|
||||
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
|
||||
@foreach (var theme in _themes)
|
||||
{
|
||||
<option value="@theme.TypeName">@theme.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultContainer" class="form-select" @bind="@_containertype" required>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultAdminContainer" class="form-select" @bind="@_admincontainertype" required>
|
||||
<option value="@Constants.DefaultAdminContainer"><@Localizer["DefaultAdminContainer"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="PageContent" Heading="Page Content" ResourceKey="PageContent">
|
||||
<div class="container">
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -124,9 +157,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="enabledSSl" HelpText="Specify if SSL is required for your SMTP server" ResourceKey="UseSsl">SSL Enabled: </Label>
|
||||
<Label Class="col-sm-3" For="smtpssl" HelpText="Specify if SSL is required for your SMTP server" ResourceKey="UseSsl">SSL Enabled: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="enabledSSl" class="form-select" @bind="@_smtpssl" >
|
||||
<select id="smtpssl" class="form-select" @bind="@_smtpssl" >
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
@ -162,7 +195,16 @@
|
||||
</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="smtpenabled" HelpText="Specify if SMTP is enabled for this site" ResourceKey="SMTPEnabled">Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="smtpenabled" class="form-select" @bind="@_smtpenabled">
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" @bind="@_retention" />
|
||||
@ -201,53 +243,53 @@
|
||||
{
|
||||
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="aliases" HelpText="The list of aliases for this site" ResourceKey="Aliases">Aliases: </Label>
|
||||
<div class="col-sm-9">
|
||||
<button type="button" class="btn btn-primary" @onclick="AddAlias">@SharedLocalizer["Add"]</button>
|
||||
<Pager Items="@_aliases">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["AliasName"]</th>
|
||||
<th>@Localizer["AliasDefault"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
@if (context.AliasId != _aliasid)
|
||||
{
|
||||
<td>
|
||||
@if (_aliasid == -1)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick="@(() => EditAlias(context))">@SharedLocalizer["Edit"]</button>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (_aliasid == -1)
|
||||
{
|
||||
<ActionDialog Action="Delete" OnClick="@(async () => await DeleteAlias(context))" ResourceKey="DeleteModule" Class="btn btn-danger" Header="Delete Alias" Message="@string.Format(Localizer["Confirm.Alias.Delete", context.Name])" />
|
||||
}
|
||||
</td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.IsDefault</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<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>
|
||||
<input id="aliasname" class="form-control" @bind="@_aliasname" />
|
||||
</td>
|
||||
<td>
|
||||
<select id="defaultaias" class="form-select" @bind="@_defaultalias" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</td>
|
||||
}
|
||||
</Row>
|
||||
</Pager>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<button type="button" class="btn btn-primary" @onclick="AddAlias">@SharedLocalizer["Add"]</button>
|
||||
<Pager Items="@_aliases">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["AliasName"]</th>
|
||||
<th>@Localizer["AliasDefault"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
@if (context.AliasId != _aliasid)
|
||||
{
|
||||
<td>
|
||||
@if (_aliasid == -1)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick="@(() => EditAlias(context))">@SharedLocalizer["Edit"]</button>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@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])" />
|
||||
}
|
||||
</td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.IsDefault</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<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>
|
||||
<input id="aliasname" class="form-control" @bind="@_aliasname" />
|
||||
</td>
|
||||
<td>
|
||||
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</td>
|
||||
}
|
||||
</Row>
|
||||
</Pager>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
|
||||
@ -306,222 +348,236 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private bool _initialized = false;
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name = string.Empty;
|
||||
private List<Alias> _aliases;
|
||||
private int _aliasid = -1;
|
||||
private string _aliasname;
|
||||
private string _defaultalias;
|
||||
private string _runtime = "";
|
||||
private string _prerender = "";
|
||||
private int _logofileid = -1;
|
||||
private FileManager _logofilemanager;
|
||||
private int _faviconfileid = -1;
|
||||
private FileManager _faviconfilemanager;
|
||||
private string _themetype = "-";
|
||||
private string _containertype = "-";
|
||||
private string _admincontainertype = "-";
|
||||
private string _homepageid = "-";
|
||||
private string _sitemap = "";
|
||||
private string _smtphost = string.Empty;
|
||||
private string _smtpport = string.Empty;
|
||||
private string _smtpssl = "False";
|
||||
private string _smtpusername = string.Empty;
|
||||
private string _smtppassword = string.Empty;
|
||||
private string _smtppasswordtype = "password";
|
||||
private string _togglesmtppassword = string.Empty;
|
||||
private string _smtpsender = string.Empty;
|
||||
private string _smtprelay = "False";
|
||||
private string _retention = string.Empty;
|
||||
private string _pwaisenabled;
|
||||
private int _pwaappiconfileid = -1;
|
||||
private FileManager _pwaappiconfilemanager;
|
||||
private int _pwasplashiconfileid = -1;
|
||||
private FileManager _pwasplashiconfilemanager;
|
||||
private string _tenant = string.Empty;
|
||||
private string _database = string.Empty;
|
||||
private string _connectionstring = string.Empty;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private string _deletedby;
|
||||
private DateTime? _deletedon;
|
||||
private string _isdeleted;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private bool _initialized = false;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name = string.Empty;
|
||||
private string _homepageid = "-";
|
||||
private string _isdeleted;
|
||||
private string _sitemap = "";
|
||||
private string _siteguid = "";
|
||||
private string _version = "";
|
||||
private int _logofileid = -1;
|
||||
private FileManager _logofilemanager;
|
||||
private int _faviconfileid = -1;
|
||||
private FileManager _faviconfilemanager;
|
||||
private string _themetype = "";
|
||||
private string _containertype = "";
|
||||
private string _admincontainertype = "";
|
||||
private string _headcontent = string.Empty;
|
||||
private string _bodycontent = string.Empty;
|
||||
private string _smtphost = string.Empty;
|
||||
private string _smtpport = string.Empty;
|
||||
private string _smtpssl = "False";
|
||||
private string _smtpusername = string.Empty;
|
||||
private string _smtppassword = string.Empty;
|
||||
private string _smtppasswordtype = "password";
|
||||
private string _togglesmtppassword = string.Empty;
|
||||
private string _smtpsender = string.Empty;
|
||||
private string _smtprelay = "False";
|
||||
private string _smtpenabled = "True";
|
||||
private string _retention = string.Empty;
|
||||
private string _pwaisenabled;
|
||||
private int _pwaappiconfileid = -1;
|
||||
private FileManager _pwaappiconfilemanager;
|
||||
private int _pwasplashiconfileid = -1;
|
||||
private FileManager _pwasplashiconfilemanager;
|
||||
private List<Alias> _aliases;
|
||||
private int _aliasid = -1;
|
||||
private string _aliasname;
|
||||
private string _defaultalias;
|
||||
private string _runtime = "";
|
||||
private string _prerender = "";
|
||||
private string _tenant = string.Empty;
|
||||
private string _database = string.Empty;
|
||||
private string _connectionstring = string.Empty;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private string _deletedby;
|
||||
private DateTime? _deletedon;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
_name = site.Name;
|
||||
_runtime = site.Runtime;
|
||||
_prerender = site.RenderMode.Replace(_runtime, "");
|
||||
_isdeleted = site.IsDeleted.ToString();
|
||||
_sitemap = PageState.Alias.Protocol + PageState.Alias.Name + "/pages/sitemap.xml";
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
_name = site.Name;
|
||||
if (site.HomePageId != null)
|
||||
{
|
||||
_homepageid = site.HomePageId.Value.ToString();
|
||||
}
|
||||
_isdeleted = site.IsDeleted.ToString();
|
||||
_sitemap = PageState.Alias.Protocol + PageState.Alias.Name + "/pages/sitemap.xml";
|
||||
_siteguid = site.SiteGuid;
|
||||
_version = site.Version;
|
||||
|
||||
await GetAliases();
|
||||
// appearance
|
||||
if (site.LogoFileId != null)
|
||||
{
|
||||
_logofileid = site.LogoFileId.Value;
|
||||
}
|
||||
|
||||
if (site.LogoFileId != null)
|
||||
{
|
||||
_logofileid = site.LogoFileId.Value;
|
||||
}
|
||||
if (site.FaviconFileId != null)
|
||||
{
|
||||
_faviconfileid = site.FaviconFileId.Value;
|
||||
}
|
||||
_themes = ThemeService.GetThemeControls(PageState.Site.Themes);
|
||||
_themetype = (!string.IsNullOrEmpty(site.DefaultThemeType)) ? site.DefaultThemeType : Constants.DefaultTheme;
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||
|
||||
if (site.FaviconFileId != null)
|
||||
{
|
||||
_faviconfileid = site.FaviconFileId.Value;
|
||||
}
|
||||
// page content
|
||||
_headcontent = site.HeadContent;
|
||||
_bodycontent = site.BodyContent;
|
||||
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
_themetype = (!string.IsNullOrEmpty(site.DefaultThemeType)) ? site.DefaultThemeType : Constants.DefaultTheme;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||
// PWA
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
|
||||
if (site.HomePageId != null)
|
||||
{
|
||||
_homepageid = site.HomePageId.Value.ToString();
|
||||
}
|
||||
// SMTP
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||
_smtprelay = SettingService.GetSetting(settings, "SMTPRelay", "False");
|
||||
_smtpenabled = SettingService.GetSetting(settings, "SMTPEnabled", "True");
|
||||
_retention = SettingService.GetSetting(settings, "NotificationRetention", "30");
|
||||
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
// aliases
|
||||
await GetAliases();
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||
_smtprelay = SettingService.GetSetting(settings, "SMTPRelay", "False");
|
||||
_retention = SettingService.GetSetting(settings, "NotificationRetention", "30");
|
||||
// hosting model
|
||||
_runtime = site.Runtime;
|
||||
_prerender = site.RenderMode.Replace(_runtime, "");
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var tenants = await TenantService.GetTenantsAsync();
|
||||
var _databases = await DatabaseService.GetDatabasesAsync();
|
||||
var tenant = tenants.Find(item => item.TenantId == site.TenantId);
|
||||
if (tenant != null)
|
||||
{
|
||||
_tenant = tenant.Name;
|
||||
_database = _databases.Find(item => item.DBType == tenant.DBType)?.Name;
|
||||
_connectionstring = tenant.DBConnectionString;
|
||||
}
|
||||
}
|
||||
// database
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var tenants = await TenantService.GetTenantsAsync();
|
||||
var _databases = await DatabaseService.GetDatabasesAsync();
|
||||
var tenant = tenants.Find(item => item.TenantId == site.TenantId);
|
||||
if (tenant != null)
|
||||
{
|
||||
_tenant = tenant.Name;
|
||||
_database = _databases.Find(item => item.DBType == tenant.DBType)?.Name;
|
||||
_connectionstring = tenant.DBConnectionString;
|
||||
}
|
||||
}
|
||||
|
||||
_createdby = site.CreatedBy;
|
||||
_createdon = site.CreatedOn;
|
||||
_modifiedby = site.ModifiedBy;
|
||||
_modifiedon = site.ModifiedOn;
|
||||
_deletedby = site.DeletedBy;
|
||||
_deletedon = site.DeletedOn;
|
||||
// audit
|
||||
_createdby = site.CreatedBy;
|
||||
_createdon = site.CreatedOn;
|
||||
_modifiedby = site.ModifiedBy;
|
||||
_modifiedon = site.ModifiedOn;
|
||||
_deletedby = site.DeletedBy;
|
||||
_deletedon = site.DeletedOn;
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
if (_themetype != "-")
|
||||
{
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
}
|
||||
else
|
||||
{
|
||||
_containers = new List<ThemeControl>();
|
||||
}
|
||||
_containertype = "-";
|
||||
_admincontainertype = Constants.DefaultAdminContainer;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.LoadPane"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||
_containertype = _containers.First().TypeName;
|
||||
_admincontainertype = Constants.DefaultAdminContainer;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.LoadPane"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSite()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_name != string.Empty && _themetype != "-" && _containertype != "-")
|
||||
{
|
||||
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
bool refresh = false;
|
||||
bool reload = false;
|
||||
private async Task SaveSite()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_name != string.Empty && _themetype != "-" && _containertype != "-")
|
||||
{
|
||||
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
bool refresh = false;
|
||||
bool reload = false;
|
||||
|
||||
site.Name = _name;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender)
|
||||
{
|
||||
site.Runtime = _runtime;
|
||||
site.RenderMode = _runtime + _prerender;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
}
|
||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||
site.Name = _name;
|
||||
site.HomePageId = (_homepageid != "-" ? int.Parse(_homepageid) : null);
|
||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||
|
||||
site.LogoFileId = null;
|
||||
var logofileid = _logofilemanager.GetFileId();
|
||||
if (logofileid != -1)
|
||||
{
|
||||
site.LogoFileId = logofileid;
|
||||
}
|
||||
int? faviconFieldId = _faviconfilemanager.GetFileId();
|
||||
if (faviconFieldId == -1) faviconFieldId = null;
|
||||
if (site.FaviconFileId != faviconFieldId)
|
||||
{
|
||||
site.FaviconFileId = faviconFieldId;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
if (site.DefaultThemeType != _themetype)
|
||||
{
|
||||
site.DefaultThemeType = _themetype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
if (site.DefaultContainerType != _containertype)
|
||||
{
|
||||
site.DefaultContainerType = _containertype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
site.AdminContainerType = _admincontainertype;
|
||||
site.HomePageId = (_homepageid != "-" ? int.Parse(_homepageid) : null);
|
||||
// appearance
|
||||
site.LogoFileId = null;
|
||||
var logofileid = _logofilemanager.GetFileId();
|
||||
if (logofileid != -1)
|
||||
{
|
||||
site.LogoFileId = logofileid;
|
||||
}
|
||||
int? faviconFieldId = _faviconfilemanager.GetFileId();
|
||||
if (faviconFieldId == -1) faviconFieldId = null;
|
||||
if (site.FaviconFileId != faviconFieldId)
|
||||
{
|
||||
site.FaviconFileId = faviconFieldId;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
if (site.DefaultThemeType != _themetype)
|
||||
{
|
||||
site.DefaultThemeType = _themetype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
if (site.DefaultContainerType != _containertype)
|
||||
{
|
||||
site.DefaultContainerType = _containertype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
site.AdminContainerType = _admincontainertype;
|
||||
|
||||
// page content
|
||||
if (site.HeadContent != _headcontent)
|
||||
{
|
||||
site.HeadContent = _headcontent;
|
||||
reload = true;
|
||||
}
|
||||
if (site.BodyContent != _bodycontent)
|
||||
{
|
||||
site.BodyContent = _bodycontent;
|
||||
reload = true;
|
||||
}
|
||||
|
||||
// PWA
|
||||
if (site.PwaIsEnabled.ToString() != _pwaisenabled)
|
||||
{
|
||||
site.PwaIsEnabled = Boolean.Parse(_pwaisenabled);
|
||||
@ -542,17 +598,31 @@
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
|
||||
// hosting model
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender)
|
||||
{
|
||||
site.Runtime = _runtime;
|
||||
site.RenderMode = _runtime + _prerender;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
}
|
||||
|
||||
site = await SiteService.UpdateSiteAsync(site);
|
||||
|
||||
// SMTP
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
||||
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||
|
||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||
@ -564,8 +634,8 @@
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
await ScrollToPageTop();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -633,9 +703,8 @@
|
||||
|
||||
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
||||
AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
await ScrollToPageTop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Testing SMTP Configuration");
|
||||
|
@ -29,7 +29,7 @@ else
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="alias" HelpText="Enter the aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder)." ResourceKey="Aliases">Aliases: </Label>
|
||||
<Label Class="col-sm-3" For="alias" HelpText="The urls for the site (comman delimited). This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder)." ResourceKey="Aliases">Urls: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" required></textarea>
|
||||
</div>
|
||||
@ -288,12 +288,13 @@ else
|
||||
if (_themetype != "-")
|
||||
{
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
}
|
||||
_containertype = _containers.First().TypeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
_containers = new List<ThemeControl>();
|
||||
}
|
||||
_containertype = "-";
|
||||
_containertype = "-";
|
||||
}
|
||||
_admincontainertype = "";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
@ -8,17 +8,17 @@
|
||||
|
||||
@if (_sites == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
<p><em>@SharedLocalizer["Loading"]</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ActionLink Action="Add" Text="Add Site" ResourceKey="AddSite" />
|
||||
|
||||
<Pager Items="@_sites">
|
||||
<Pager Items="@_sites" SearchProperties="Name">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@Localizer["AliasName"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><button type="button" class="btn btn-primary" @onclick="@(async () => Edit(context.Name))">@SharedLocalizer["Edit"]</button></td>
|
||||
|
@ -133,12 +133,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="packageservice" HelpText="Specify If The Package Service Is Enabled For Installing Modules, Themes, And Translations" ResourceKey="PackageService">Enable Package Service? </Label>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<select id="packageservice" class="form-select" @bind="@_packageservice">
|
||||
<option value="true">@SharedLocalizer["True"]</option>
|
||||
<option value="false">@SharedLocalizer["False"]</option>
|
||||
</select>
|
||||
<input id="packageregistryurl" class="form-control" @bind="@_packageregistryurl" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -182,7 +179,7 @@
|
||||
private string _logginglevel = string.Empty;
|
||||
private string _notificationlevel = string.Empty;
|
||||
private string _swagger = string.Empty;
|
||||
private string _packageservice = string.Empty;
|
||||
private string _packageregistryurl = string.Empty;
|
||||
|
||||
private string _log = string.Empty;
|
||||
|
||||
@ -213,7 +210,7 @@
|
||||
_logginglevel = systeminfo["Logging:LogLevel:Default"].ToString();
|
||||
_notificationlevel = systeminfo["Logging:LogLevel:Notify"].ToString();
|
||||
_swagger = systeminfo["UseSwagger"].ToString();
|
||||
_packageservice = systeminfo["PackageService"].ToString();
|
||||
_packageregistryurl = systeminfo["PackageRegistryUrl"].ToString();
|
||||
}
|
||||
|
||||
systeminfo = await SystemService.GetSystemInfoAsync("log");
|
||||
@ -232,7 +229,7 @@
|
||||
settings.Add("Logging:LogLevel:Default", _logginglevel);
|
||||
settings.Add("Logging:LogLevel:Notify", _notificationlevel);
|
||||
settings.Add("UseSwagger", _swagger);
|
||||
settings.Add("PackageService", _packageservice);
|
||||
settings.Add("PackageRegistryUrl", _packageregistryurl);
|
||||
await SystemService.UpdateSystemInfoAsync(settings);
|
||||
AddModuleMessage(Localizer["Success.UpdateConfig.Restart"], MessageType.Success);
|
||||
}
|
||||
|
@ -10,61 +10,115 @@
|
||||
<TabStrip>
|
||||
<TabPanel Name="Download" ResourceKey="Download">
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<select id="price" class="form-select custom-select" @onchange="(e => PriceChanged(e))">
|
||||
<option value="free">@SharedLocalizer["Free"]</option>
|
||||
<option value="paid">@SharedLocalizer["Paid"]</option>
|
||||
</select>
|
||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||
<div class="text-center">
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="free" class="form-check-input" type="radio" checked="@(_price == "free")" name="Price" @onchange="@(() => PriceChanged("free"))" />
|
||||
<label class="form-check-label" for="free">@SharedLocalizer["Free"]</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input id="paid" class="form-check-input" type="radio" checked="@(_price == "paid")" name="Price" @onchange="@(() => PriceChanged("paid"))" />
|
||||
<label class="form-check-label" for="paid">@SharedLocalizer["Paid"]</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (_packages != null)
|
||||
{
|
||||
if (_packages.Count > 0)
|
||||
{
|
||||
<Pager Items="@_packages">
|
||||
<Row>
|
||||
<td>
|
||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_new">@context.Name</a></h3> @SharedLocalizer["Search.By"]: <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
||||
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
||||
@((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(context.PackageUrl).Host + "</strong>" : ""))
|
||||
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
||||
</td>
|
||||
<td style="width: 1px; vertical-align: middle;">
|
||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PackageUrl))
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
</td>
|
||||
<td style="width: 1px; vertical-align: middle;">
|
||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
||||
{
|
||||
<a class="btn btn-primary" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@context.Price.Value.ToString("$#,##0.00")</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
else
|
||||
{
|
||||
<br />
|
||||
<div class="mx-auto text-center">
|
||||
@Localizer["Search.NoResults"]
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">@Localizer["Product"]</span>
|
||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||
<button type="button" class="btn btn-primary ms-2" @onclick="Refresh"><span class="@Icons.Reload" aria-hidden="true"></span></button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col">
|
||||
@if (_initialized)
|
||||
{
|
||||
<br />
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-4">
|
||||
<h3>@((_packages != null) ? _packages.Count : 0) @SharedLocalizer["Search.Results"]</h3>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-select" value="@_sort" @onchange="(e => SortChanged(e))">
|
||||
<option value="popularity">@SharedLocalizer["Search.Popularity"]</option>
|
||||
<option value="alphabetical">@SharedLocalizer["Search.Alphabetical"]</option>
|
||||
@if (_price == "free")
|
||||
{
|
||||
<option value="downloads">@SharedLocalizer["Search.Downloads"]</option>
|
||||
}
|
||||
<option value="recent">@SharedLocalizer["Search.RecentlyReleased"]</option>
|
||||
@if (_price == "paid")
|
||||
{
|
||||
<option value="price">@SharedLocalizer["Search.Price"]</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<Pager Format="Grid" Items="@_packages" DisplayPages="1" PageSize="9" Toolbar="Both" Class="container-fluid px-0" RowClass="row g-0" ColumnClass="col-lg-4 col-md-6">
|
||||
<Row>
|
||||
<div class="m-2 p-2 d-flex justify-content-center">
|
||||
<div class="container-fluid px-0">
|
||||
<div class="row g-0 mb-2">
|
||||
<div class="col-4">
|
||||
<a href="@context.ProductUrl" target="_blank">
|
||||
@if (context.LogoUrl != null)
|
||||
{
|
||||
<img src="@context.LogoUrl" class="img-fluid" alt="@context.Name" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<img src="/package.png" class="img-fluid" alt="@context.Name" />
|
||||
}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-8 text-end">
|
||||
<small>@SharedLocalizer["Search.Version"]:</small> <strong>@context.Version</strong>
|
||||
<br /><small>@SharedLocalizer["Search.Released"]:</small> <strong>@context.ReleaseDate.ToString("MM/dd/yyyy")</strong>
|
||||
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||
{
|
||||
<br /><small>@SharedLocalizer["Search.Source"]:</small> <strong>@(new Uri(context.PackageUrl).Host)</strong>
|
||||
}
|
||||
@if (context.Price == null)
|
||||
{
|
||||
<br /><small>@SharedLocalizer["Search.Downloads"]:</small> <strong>@(String.Format("{0:n0}", context.Downloads))</strong>
|
||||
}
|
||||
else
|
||||
{
|
||||
<br /><small>@SharedLocalizer["From"]:</small> <strong>@context.Price.Value.ToString("$#,##0.00")</strong>
|
||||
@((MarkupString)(context.TrialPeriod > 0 ? " <strong>(" + context.TrialPeriod + " Day Trial)</strong>" : ""))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-0">
|
||||
<div class="col">
|
||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_blank">@context.Name</a></h3><br />
|
||||
<small>@SharedLocalizer["Search.By"]:</small> <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
||||
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
||||
<br />
|
||||
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
||||
{
|
||||
<a class="btn btn-success ms-2" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@SharedLocalizer["Buy"]</a>
|
||||
}
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
||||
</TabPanel>
|
||||
@ -116,8 +170,11 @@
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private int _page = 1;
|
||||
private List<Package> _packages;
|
||||
private string _price = "free";
|
||||
private string _sort = "popularity";
|
||||
private string _search = "";
|
||||
private string _productname = "";
|
||||
private string _license = "";
|
||||
@ -131,6 +188,7 @@
|
||||
try
|
||||
{
|
||||
await LoadThemes();
|
||||
_initialized = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -141,8 +199,10 @@
|
||||
|
||||
private async Task LoadThemes()
|
||||
{
|
||||
ShowProgressIndicator();
|
||||
|
||||
var themes = await ThemeService.GetThemesAsync();
|
||||
_packages = await PackageService.GetPackagesAsync("theme", _search, _price, "");
|
||||
_packages = await PackageService.GetPackagesAsync("theme", _search, _price, "", _sort);
|
||||
|
||||
if (_packages != null)
|
||||
{
|
||||
@ -154,46 +214,44 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HideProgressIndicator();
|
||||
}
|
||||
|
||||
private async void PriceChanged(ChangeEventArgs e)
|
||||
private async void PriceChanged(string price)
|
||||
{
|
||||
try
|
||||
{
|
||||
_price = (string)e.Value;
|
||||
_search = "";
|
||||
await LoadThemes();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On PriceChanged");
|
||||
}
|
||||
_price = price;
|
||||
_sort = "popularity";
|
||||
await LoadThemes();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task Search()
|
||||
{
|
||||
try
|
||||
{
|
||||
await LoadThemes();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On Search");
|
||||
}
|
||||
await LoadThemes();
|
||||
}
|
||||
|
||||
private async Task Reset()
|
||||
{
|
||||
try
|
||||
{
|
||||
_search = "";
|
||||
await LoadThemes();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On Reset");
|
||||
}
|
||||
_page = 1;
|
||||
_search = "";
|
||||
await LoadThemes();
|
||||
}
|
||||
|
||||
private async Task Refresh()
|
||||
{
|
||||
await LoadThemes();
|
||||
}
|
||||
|
||||
private void OnPageChange(int page)
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
private async void SortChanged(ChangeEventArgs e)
|
||||
{
|
||||
_sort = (string)e.Value;
|
||||
await LoadThemes();
|
||||
}
|
||||
|
||||
private void HideModal()
|
||||
@ -207,7 +265,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
var package = await PackageService.GetPackageAsync(packageid, version);
|
||||
var package = await PackageService.GetPackageAsync(packageid, version, false);
|
||||
if (package != null)
|
||||
{
|
||||
_productname = package.Name;
|
||||
@ -217,8 +275,13 @@
|
||||
}
|
||||
_packageid = package.PackageId;
|
||||
_version = package.Version;
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError("Error Getting Package {PackageId} {Version}", packageid, version);
|
||||
AddModuleMessage(Localizer["Error.Theme.Download"], MessageType.Error);
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -231,7 +294,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
||||
await PackageService.DownloadPackageAsync(_packageid, _version);
|
||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
_productname = "";
|
||||
|
@ -80,7 +80,10 @@
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
AddModuleMessage(Localizer["Info.Theme.CreatorIntent"], MessageType.Info);
|
||||
if (!NavigationManager.BaseUri.Contains("localhost:"))
|
||||
{
|
||||
AddModuleMessage(Localizer["Info.Theme.CreatorIntent"], MessageType.Info);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
@ -102,7 +105,8 @@
|
||||
{
|
||||
if (IsValid(_owner) && IsValid(_theme) && _owner != _theme && _template != "-")
|
||||
{
|
||||
var theme = new Theme { Owner = _owner, Name = _theme, Template = _template, Version = _reference };
|
||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||
var theme = new Theme { Owner = _owner, Name = _theme, Template = _template, Version = _reference, ThemeName = template.Namespace };
|
||||
theme = await ThemeService.CreateThemeAsync(theme);
|
||||
GetLocation();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Create"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
@ -142,8 +146,14 @@
|
||||
if (_owner != "" && _theme != "" && _template != "-")
|
||||
{
|
||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||
_location = template.Location + _owner + "." + _theme;
|
||||
|
||||
if (!string.IsNullOrEmpty(template.Namespace))
|
||||
{
|
||||
_location = template.Location + template.Namespace.Replace("[Owner]", _owner).Replace("[Theme]", _theme);
|
||||
}
|
||||
else
|
||||
{
|
||||
_location = template.Location + _owner + ".Theme." + _theme;
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
211
Oqtane.Client/Modules/Admin/Themes/Edit.razor
Normal file
211
Oqtane.Client/Modules/Admin/Themes/Edit.razor
Normal file
@ -0,0 +1,211 @@
|
||||
@namespace Oqtane.Modules.Admin.Themes
|
||||
@using System.Net
|
||||
@inherits ModuleBase
|
||||
@inject IThemeService ThemeService
|
||||
@inject IPackageService PackageService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_initialized)
|
||||
{
|
||||
<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="name" HelpText="The name of the module" ResourceKey="Name">Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="name" class="form-control" @bind="@_name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isenabled" HelpText="Is theme enabled for this site?" ResourceKey="IsEnabled">Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isenabled" class="form-select" @bind="@_isenabled" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<Section Name="Information" ResourceKey="Information" Heading="Information">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="themename" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="themename" class="form-control" @bind="@_themeName" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="version" HelpText="The version of the theme" ResourceKey="Version">Version: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="version" class="form-control" @bind="@_version" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
@if (!string.IsNullOrEmpty(_packagename))
|
||||
{
|
||||
<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 class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the theme" ResourceKey="Owner">Owner: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="owner" class="form-control" @bind="@_owner" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="contact" HelpText="The contact for the theme" ResourceKey="Contact">Contact: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="contact" class="form-control" @bind="@_contact" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="license" HelpText="The license of the theme" ResourceKey="License">License: </Label>
|
||||
<div class="col-sm-9">
|
||||
@if (_license.StartsWith("http") || _license.StartsWith("/") || _license.StartsWith("~"))
|
||||
{
|
||||
<a href="@_license.Replace("~", PageState?.Alias.BaseUrl + "/Themes/" + Utilities.GetTypeName(_themeName))" class="btn btn-info" style="text-decoration: none !important" target="_new">@Localizer["View License"]</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveTheme">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
<br />
|
||||
<br />
|
||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private int _themeId;
|
||||
private string _themeName = "";
|
||||
private string _isenabled;
|
||||
private string _name;
|
||||
private string _version;
|
||||
private string _packagename = "";
|
||||
private string _packageurl = "";
|
||||
private string _owner = "";
|
||||
private string _url = "";
|
||||
private string _contact = "";
|
||||
private string _license = "";
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeId = Int32.Parse(PageState.QueryString["id"]);
|
||||
var theme = await ThemeService.GetThemeAsync(_themeId, ModuleState.SiteId);
|
||||
if (theme != null)
|
||||
{
|
||||
_name = theme.Name;
|
||||
_isenabled =theme.IsEnabled.ToString();
|
||||
_version = theme.Version;
|
||||
_packagename = theme.PackageName;
|
||||
_owner = theme.Owner;
|
||||
_url = theme.Url;
|
||||
_contact = theme.Contact;
|
||||
_license = theme.License;
|
||||
_createdby = theme.CreatedBy;
|
||||
_createdon = theme.CreatedOn;
|
||||
_modifiedby = theme.ModifiedBy;
|
||||
_modifiedon = theme.ModifiedOn;
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Theme {ThemeName} {Error}", _themeName, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.Loading"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveTheme()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
var theme = await ThemeService.GetThemeAsync(_themeId, ModuleState.SiteId);
|
||||
theme.Name = _name;
|
||||
theme.IsEnabled = (_isenabled == null ? true : bool.Parse(_isenabled));
|
||||
await ThemeService.UpdateThemeAsync(theme);
|
||||
await logger.LogInformation("Theme Saved {Theme}", theme);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Theme {ThemeId} {Error}", _themeId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Save"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<ActionLink Action="Add" Text="Install Theme" />
|
||||
<ActionLink Action="Add" Text="Install Theme" ResourceKey="InstallTheme" />
|
||||
@((MarkupString)" ")
|
||||
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" Class="btn btn-secondary" />
|
||||
|
||||
@ -23,11 +23,13 @@ else
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@SharedLocalizer["Version"]</th>
|
||||
<th>@Localizer["Enabled"]</th>
|
||||
<th>@SharedLocalizer["Support"]</th>
|
||||
<th>@SharedLocalizer["Expires"]</th>
|
||||
<th> </th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="View" Parameters="@($"name=" + WebUtility.UrlEncode(context.ThemeName))" ResourceKey="ViewTheme" /></td>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditTheme" /></td>
|
||||
<td>
|
||||
@if (context.AssemblyName != Constants.ClientId)
|
||||
{
|
||||
@ -36,6 +38,19 @@ else
|
||||
</td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Version</td>
|
||||
<td>
|
||||
@if (context.IsEnabled)
|
||||
{
|
||||
<span>@SharedLocalizer["Yes"]</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@SharedLocalizer["No"]</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@((MarkupString)SupportLink(context.PackageName, context.Version))
|
||||
</td>
|
||||
<td>
|
||||
@((MarkupString)PurchaseLink(context.PackageName))
|
||||
</td>
|
||||
@ -64,7 +79,7 @@ else
|
||||
try
|
||||
{
|
||||
_themes = await ThemeService.GetThemesAsync();
|
||||
_packages = await PackageService.GetPackagesAsync("theme");
|
||||
_packages = await PackageService.GetPackageUpdatesAsync("theme");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -85,11 +100,14 @@ else
|
||||
if (package != null)
|
||||
{
|
||||
if (package.ExpiryDate != null && package.ExpiryDate.Value.Date != DateTime.MaxValue.Date)
|
||||
{
|
||||
link += "<span>" + package.ExpiryDate.Value.Date.ToString("MMM dd, yyyy") + "</span>";
|
||||
if (!string.IsNullOrEmpty(package.PaymentUrl))
|
||||
{
|
||||
if (string.IsNullOrEmpty(package.PaymentUrl))
|
||||
{
|
||||
link += " <a class=\"btn btn-primary\" style=\"text-decoration: none !important\" href=\"" + package.PaymentUrl + "\" target=\"_new\">" + SharedLocalizer["Extend"] + "</a>";
|
||||
link = "<span>" + package.ExpiryDate.Value.Date.ToString("MMM dd, yyyy") + "</span>";
|
||||
}
|
||||
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>";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -97,6 +115,20 @@ else
|
||||
return link;
|
||||
}
|
||||
|
||||
private string SupportLink(string packagename, string version)
|
||||
{
|
||||
string link = "";
|
||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||
if (package != null && !string.IsNullOrEmpty(package.SupportUrl))
|
||||
{
|
||||
link += "<a class=\"btn btn-info\" style=\"text-decoration: none !important\" href=\"" + package.SupportUrl.Replace("{Version}", version) + "\" target=\"_new\">" + SharedLocalizer["Help"] + "</a>";
|
||||
}
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
private string UpgradeAvailable(string packagename, string version)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||
@ -114,7 +146,7 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
||||
await PackageService.DownloadPackageAsync(packagename, version);
|
||||
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", packagename, version);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
}
|
||||
|
@ -1,97 +0,0 @@
|
||||
@namespace Oqtane.Modules.Admin.Themes
|
||||
@using System.Net
|
||||
@inherits ModuleBase
|
||||
@inject IThemeService ThemeService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IStringLocalizer<View> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="name" HelpText="The name of the theme" ResourceKey="Name">Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="name" class="form-control" @bind="@_name" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="themename" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="themename" class="form-control" @bind="@_themeName" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="version" HelpText="The version of the theme" ResourceKey="Version">Version: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="version" class="form-control" @bind="@_version" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<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" ResourceKey="PackageName">Package Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the theme" ResourceKey="Owner">Owner: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="owner" class="form-control" @bind="@_owner" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="contact" HelpText="The contact for the theme" ResourceKey="Contact">Contact: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="contact" class="form-control" @bind="@_contact" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="license" HelpText="The license of the theme" ResourceKey="License">License: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private string _themeName = "";
|
||||
private string _name;
|
||||
private string _version;
|
||||
private string _packagename;
|
||||
private string _owner = "";
|
||||
private string _url = "";
|
||||
private string _contact = "";
|
||||
private string _license = "";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeName = WebUtility.UrlDecode(PageState.QueryString["name"]);
|
||||
var themes = await ThemeService.GetThemesAsync();
|
||||
var theme = themes.FirstOrDefault(item => item.ThemeName == _themeName);
|
||||
if (theme != null)
|
||||
{
|
||||
_name = theme.Name;
|
||||
_version = theme.Version;
|
||||
_packagename = theme.PackageName;
|
||||
_owner = theme.Owner;
|
||||
_url = theme.Url;
|
||||
_contact = theme.Contact;
|
||||
_license = theme.License;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Theme {ThemeName} {Error}", _themeName, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.Loading"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,34 +7,38 @@
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<TabStrip>
|
||||
<TabPanel Name="Download" ResourceKey="Download">
|
||||
@if (_package != null && _upgradeavailable)
|
||||
{
|
||||
<ModuleMessage Type="MessageType.Info" Message="Select The Download Button To Download The Framework Upgrade Package And Then Select Upgrade"></ModuleMessage>
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await Download(Constants.PackageId, @_package.Version))>@SharedLocalizer["Download"] @_package.Version</button>
|
||||
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ModuleMessage Type="MessageType.Info" Message="Framework Is Already Up To Date"></ModuleMessage>
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
||||
<ModuleMessage Type="MessageType.Info" Message="Upload A Framework Package (Oqtane.Framework.version.nupkg) And Then Select Upgrade"></ModuleMessage>
|
||||
<div class="container">
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<FileManager Folder="@Constants.PackagesFolder" />
|
||||
@if (_initialized)
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Download" ResourceKey="Download">
|
||||
@if (_package != null && _upgradeavailable)
|
||||
{
|
||||
<ModuleMessage Type="MessageType.Info" Message="Select The Download Button To Download The Framework Upgrade Package And Then Select Upgrade"></ModuleMessage>
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await Download(Constants.PackageId, @_package.Version))>@SharedLocalizer["Download"] @_package.Version</button>
|
||||
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ModuleMessage Type="MessageType.Info" Message=@Localizer["Message.Text"]></ModuleMessage>
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
||||
<ModuleMessage Type="MessageType.Info" Message=@Localizer["MessageUpgrade.Text"]></ModuleMessage>
|
||||
<div class="container">
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<FileManager Folder="@Constants.PackagesFolder" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private Package _package;
|
||||
private bool _upgradeavailable = false;
|
||||
|
||||
@ -44,18 +48,26 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Package> packages = await PackageService.GetPackagesAsync("framework", "", "", "");
|
||||
if (packages != null)
|
||||
if (NavigationManager.BaseUri.Contains("localhost:"))
|
||||
{
|
||||
_package = packages.Where(item => item.PackageId.StartsWith(Constants.PackageId)).FirstOrDefault();
|
||||
if (_package != null)
|
||||
AddModuleMessage(Localizer["Localhost.Text"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Package> packages = await PackageService.GetPackagesAsync("framework", "", "", "");
|
||||
if (packages != null)
|
||||
{
|
||||
_upgradeavailable = (Version.Parse(_package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
_package = new Package { Name = Constants.PackageId, Version = Constants.Version };
|
||||
_package = packages.Where(item => item.PackageId.StartsWith(Constants.PackageId)).FirstOrDefault();
|
||||
if (_package != null)
|
||||
{
|
||||
_upgradeavailable = (Version.Parse(_package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
_package = new Package { Name = Constants.PackageId, Version = Constants.Version };
|
||||
}
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
@ -85,8 +97,8 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(packageid, version, Constants.PackagesFolder);
|
||||
await PackageService.DownloadPackageAsync(Constants.UpdaterPackageId, version, Constants.PackagesFolder);
|
||||
await PackageService.DownloadPackageAsync(packageid, version);
|
||||
await PackageService.DownloadPackageAsync(Constants.UpdaterPackageId, version);
|
||||
AddModuleMessage(Localizer["Success.Framework.Download"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -28,7 +28,7 @@ else
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<Pager Items="@_urlMappings">
|
||||
<Pager Items="@_urlMappings" SearchProperties="Url">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
|
@ -1,4 +1,5 @@
|
||||
@namespace Oqtane.Modules.Admin.UserProfile
|
||||
@using System.Text.RegularExpressions;
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserService UserService
|
||||
@ -22,6 +23,7 @@ else
|
||||
<TabPanel Name="Identity" ResourceKey="Identity">
|
||||
@if (profiles != null && settings != null)
|
||||
{
|
||||
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
||||
<div class="container">
|
||||
<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>
|
||||
@ -121,13 +123,27 @@ else
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (p.IsRequired)
|
||||
@if (p.Rows == 1)
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
@if (p.IsRequired)
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
@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>
|
||||
}
|
||||
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>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@ -143,6 +159,11 @@ else
|
||||
<TabPanel Name="Notifications" ResourceKey="Notifications">
|
||||
@if (notifications != null)
|
||||
{
|
||||
<select class="form-select" @onchange="(e => FilterChanged(e))">
|
||||
<option value="to">@Localizer["Inbox"]</option>
|
||||
<option value="from">@Localizer["Items.Sent"]</option>
|
||||
</select>
|
||||
<br />
|
||||
<ActionLink Action="Add" Text="Send Notification" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="SendNotification" />
|
||||
<br /><br />
|
||||
@if (filter == "to")
|
||||
@ -158,22 +179,41 @@ else
|
||||
<Row>
|
||||
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" /></td>
|
||||
<td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>
|
||||
<td>@context.FromDisplayName</td>
|
||||
<td>@context.Subject</td>
|
||||
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
|
||||
|
||||
@if (context.IsRead)
|
||||
{
|
||||
<td>@context.FromDisplayName</td>
|
||||
<td>@context.Subject</td>
|
||||
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<td><b>@context.FromDisplayName</b></td>
|
||||
<td><b>@context.Subject</b></td>
|
||||
<td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
|
||||
}
|
||||
</Row>
|
||||
<Detail>
|
||||
<td colspan="2"></td>
|
||||
<td colspan="3">
|
||||
@{
|
||||
string input = "___";
|
||||
if (context.Body.Contains(input))
|
||||
{
|
||||
context.Body = context.Body.Split(input)[0];
|
||||
context.Body = context.Body.Replace("\n", "");
|
||||
context.Body = context.Body.Replace("\r", "");
|
||||
} }
|
||||
@(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body)
|
||||
string input = "___";
|
||||
if (context.Body.Contains(input))
|
||||
{
|
||||
context.Body = context.Body.Split(input)[0];
|
||||
context.Body = context.Body.Replace("\n", "");
|
||||
context.Body = context.Body.Replace("\r", "");
|
||||
}
|
||||
notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
|
||||
}
|
||||
@if (context.IsRead)
|
||||
{
|
||||
@notificationSummary
|
||||
}
|
||||
else
|
||||
{
|
||||
<b>@notificationSummary</b>
|
||||
}
|
||||
</td>
|
||||
</Detail>
|
||||
</Pager>
|
||||
@ -191,22 +231,42 @@ else
|
||||
<Row>
|
||||
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" /></td>
|
||||
<td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>
|
||||
<td>@context.ToDisplayName</td>
|
||||
<td>@context.Subject</td>
|
||||
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
|
||||
|
||||
@if (context.IsRead)
|
||||
{
|
||||
<td>@context.ToDisplayName</td>
|
||||
<td>@context.Subject</td>
|
||||
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<td><b>@context.ToDisplayName</b></td>
|
||||
<td><b>@context.Subject</b></td>
|
||||
<td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
|
||||
}
|
||||
|
||||
</Row>
|
||||
<Detail>
|
||||
<td colspan="2"></td>
|
||||
<td colspan="3">
|
||||
@{
|
||||
string input = "___";
|
||||
if (context.Body.Contains(input))
|
||||
{
|
||||
context.Body = context.Body.Split(input)[0];
|
||||
context.Body = context.Body.Replace("\n", "");
|
||||
context.Body = context.Body.Replace("\r", "");
|
||||
} }
|
||||
@(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body)
|
||||
string input = "___";
|
||||
if (context.Body.Contains(input))
|
||||
{
|
||||
context.Body = context.Body.Split(input)[0];
|
||||
context.Body = context.Body.Replace("\n", "");
|
||||
context.Body = context.Body.Replace("\r", "");
|
||||
}
|
||||
notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
|
||||
}
|
||||
@if (context.IsRead)
|
||||
{
|
||||
@notificationSummary
|
||||
}
|
||||
else
|
||||
{
|
||||
<b>@notificationSummary</b>
|
||||
}
|
||||
</td>
|
||||
</Detail>
|
||||
</Pager>
|
||||
@ -216,151 +276,152 @@ else
|
||||
<br />
|
||||
<ActionDialog Header="Clear Notifications" Message="Are You Sure You Wish To Permanently Delete All Notifications ?" Action="Delete All Notifications" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllNotifications())" ResourceKey="DeleteAllNotifications" />
|
||||
}
|
||||
<br /><hr />
|
||||
<select class="form-select" @onchange="(e => FilterChanged(e))">
|
||||
<option value="to">@Localizer["Inbox"]</option>
|
||||
<option value="from">@Localizer["Items.Sent"]</option>
|
||||
</select>
|
||||
}
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
<br /><br />
|
||||
|
||||
@code {
|
||||
private string username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private bool allowtwofactor = false;
|
||||
private string twofactor = "False";
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
private int folderid = -1;
|
||||
private int photofileid = -1;
|
||||
private File photo = null;
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
private string filter = "to";
|
||||
private List<Notification> notifications;
|
||||
private string _passwordrequirements;
|
||||
private string username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private bool allowtwofactor = false;
|
||||
private string twofactor = "False";
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
private int folderid = -1;
|
||||
private int photofileid = -1;
|
||||
private File photo = null;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
private string filter = "to";
|
||||
private List<Notification> notifications;
|
||||
private string notificationSummary = string.Empty;
|
||||
|
||||
if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"]))
|
||||
{
|
||||
allowtwofactor = (PageState.Site.Settings["LoginOptions:TwoFactor"] == "true");
|
||||
}
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||
|
||||
if (PageState.User != null)
|
||||
{
|
||||
username = PageState.User.Username;
|
||||
twofactor = PageState.User.TwoFactorRequired.ToString();
|
||||
email = PageState.User.Email;
|
||||
displayname = PageState.User.DisplayName;
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||
|
||||
// get user folder
|
||||
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
||||
if (folder != null)
|
||||
{
|
||||
folderid = folder.FolderId;
|
||||
}
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
|
||||
if (PageState.User.PhotoFileId != null)
|
||||
{
|
||||
photofileid = PageState.User.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true");
|
||||
|
||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||
if (PageState.User != null)
|
||||
{
|
||||
username = PageState.User.Username;
|
||||
twofactor = PageState.User.TwoFactorRequired.ToString();
|
||||
email = PageState.User.Email;
|
||||
displayname = PageState.User.DisplayName;
|
||||
|
||||
await LoadNotificationsAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
// get user folder
|
||||
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
||||
if (folder != null)
|
||||
{
|
||||
folderid = folder.FolderId;
|
||||
}
|
||||
|
||||
private async Task LoadNotificationsAsync()
|
||||
{
|
||||
notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
|
||||
notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
|
||||
}
|
||||
if (PageState.User.PhotoFileId != null)
|
||||
{
|
||||
photofileid = PageState.User.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||
{
|
||||
if (_password == confirm)
|
||||
{
|
||||
var user = PageState.User;
|
||||
user.Username = username;
|
||||
user.Password = _password;
|
||||
user.TwoFactorRequired = bool.Parse(twofactor);
|
||||
user.Email = email;
|
||||
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
||||
user.PhotoFileId = filemanager.GetFileId();
|
||||
if (user.PhotoFileId == -1)
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
if (user.PhotoFileId != null)
|
||||
{
|
||||
photofileid = user.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
await LoadNotificationsAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
user = await UserService.UpdateUserAsync(user);
|
||||
if (user != null)
|
||||
{
|
||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||
await logger.LogInformation("User Profile Saved");
|
||||
private async Task LoadNotificationsAsync()
|
||||
{
|
||||
notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
|
||||
notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
|
||||
}
|
||||
|
||||
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty)
|
||||
{
|
||||
if (_password == confirm)
|
||||
{
|
||||
if (ValidateProfiles())
|
||||
{
|
||||
var user = PageState.User;
|
||||
user.Username = username;
|
||||
user.Password = _password;
|
||||
user.TwoFactorRequired = bool.Parse(twofactor);
|
||||
user.Email = email;
|
||||
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
||||
user.PhotoFileId = filemanager.GetFileId();
|
||||
if (user.PhotoFileId == -1)
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
if (user.PhotoFileId != null)
|
||||
{
|
||||
photofileid = user.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
|
||||
user = await UserService.UpdateUserAsync(user);
|
||||
if (user != null)
|
||||
{
|
||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||
await logger.LogInformation("User Profile Saved");
|
||||
|
||||
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Invalid"], MessageType.Warning);
|
||||
@ -370,6 +431,8 @@ else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning);
|
||||
}
|
||||
|
||||
await ScrollToPageTop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -380,7 +443,6 @@ else
|
||||
|
||||
private bool ValidateProfiles()
|
||||
{
|
||||
bool valid = true;
|
||||
foreach (Profile profile in profiles)
|
||||
{
|
||||
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
|
||||
@ -391,11 +453,22 @@ else
|
||||
{
|
||||
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
{
|
||||
valid = false;
|
||||
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
|
||||
return false;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(profile.Validation))
|
||||
{
|
||||
Regex regex = new Regex(profile.Validation);
|
||||
bool valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
||||
if (!valid)
|
||||
{
|
||||
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Cancel()
|
||||
|
@ -55,7 +55,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<label class="col-sm-3">@Localizer["Message"] </label>
|
||||
<div class="col-sm-9">
|
||||
<textarea class="form-control" @bind="@body" rows="5" readonly />
|
||||
<textarea id="txtFrom" class="form-control" @bind="@body" rows="5" readonly />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<label class="col-sm-3">@Localizer["Message"] </label>
|
||||
<div class="col-sm-9">
|
||||
<textarea class="form-control" @bind="@body" rows="5" readonly />
|
||||
<textarea id="txtTo" class="form-control" @bind="@body" rows="5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -93,7 +93,7 @@
|
||||
{
|
||||
<div class="control-group">
|
||||
<label class="control-label">@Localizer["OriginalMessage"] </label>
|
||||
<textarea class="form-control" @bind="@reply" rows="5" readonly />
|
||||
<textarea id="txtReply" class="form-control" @bind="@reply" rows="5" readonly />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@ -118,6 +118,9 @@
|
||||
Notification notification = await NotificationService.GetNotificationAsync(notificationid);
|
||||
if (notification != null)
|
||||
{
|
||||
notification.IsRead = true;
|
||||
notification = await NotificationService.UpdateNotificationAsync(notification);
|
||||
|
||||
int userid = -1;
|
||||
if (notification.ToUserId == PageState.User.UserId)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
@namespace Oqtane.Modules.Admin.Users
|
||||
@using System.Text.RegularExpressions;
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserService UserService
|
||||
@ -11,11 +12,12 @@
|
||||
<TabPanel Name="Identity" ResourceKey="Identity">
|
||||
@if (profiles != null)
|
||||
{
|
||||
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="username" HelpText="A unique username for a user. 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" />
|
||||
<input id="username" class="form-control" @bind="@_username" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -31,7 +33,7 @@
|
||||
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value 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 />
|
||||
<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>
|
||||
@ -39,17 +41,25 @@
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<input id="email" class="form-control" @bind="@email" />
|
||||
<input id="email" class="form-control" @bind="@_email" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="displayname" class="form-control" @bind="@displayname" />
|
||||
<input id="displayname" class="form-control" @bind="@_displayname" />
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<select id="notify" class="form-select" @bind="@_notify" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Profile" ResourceKey="Profile">
|
||||
@ -70,18 +80,50 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
||||
<div class="col-sm-9">
|
||||
@if (p.IsRequired)
|
||||
@if (!string.IsNullOrEmpty(p.Options))
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @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))
|
||||
{
|
||||
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
|
||||
{
|
||||
<option value="@option" selected>@option</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@option">@option</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
@if (p.Rows == 1)
|
||||
{
|
||||
@if (p.IsRequired)
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@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>
|
||||
}
|
||||
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>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@ -93,13 +135,15 @@
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private string username = string.Empty;
|
||||
private string _passwordrequirements;
|
||||
private string _username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string _confirm = string.Empty;
|
||||
private string _email = string.Empty;
|
||||
private string _displayname = string.Empty;
|
||||
private string _notify = "True";
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
@ -110,6 +154,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||
settings = new Dictionary<string, string>();
|
||||
@ -121,34 +166,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private async Task SaveUser()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username != string.Empty && _password != string.Empty && confirm != string.Empty && email != string.Empty && ValidateProfiles())
|
||||
if (_username != string.Empty && _password != string.Empty && _confirm != string.Empty && _email != string.Empty)
|
||||
{
|
||||
if (_password == confirm)
|
||||
if (_password == _confirm)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(username, PageState.Site.SiteId);
|
||||
if (user == null)
|
||||
if (ValidateProfiles())
|
||||
{
|
||||
user = new User();
|
||||
var user = new User();
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = username;
|
||||
user.Username = _username;
|
||||
user.Password = _password;
|
||||
user.Email = email;
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||
user.Email = _email;
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
||||
user.PhotoFileId = null;
|
||||
user.SuppressNotification = !bool.Parse(_notify);
|
||||
|
||||
user = await UserService.AddUserAsync(user);
|
||||
|
||||
@ -160,14 +205,10 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError("Error Adding User {Username} {Email}", username, email);
|
||||
await logger.LogError("Error Adding User {Username} {Email}", _username, _email);
|
||||
AddModuleMessage(Localizer["Error.User.AddCheckPass"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Username.Exists"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -181,26 +222,39 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", username, email, ex.Message);
|
||||
await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", _username, _email, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.User.Add"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateProfiles()
|
||||
{
|
||||
bool valid = true;
|
||||
foreach (Profile profile in profiles)
|
||||
{
|
||||
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
|
||||
}
|
||||
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
valid = false;
|
||||
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
{
|
||||
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
|
||||
return false;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(profile.Validation))
|
||||
{
|
||||
Regex regex = new Regex(profile.Validation);
|
||||
bool valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
||||
if (!valid)
|
||||
{
|
||||
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
||||
|
@ -1,4 +1,5 @@
|
||||
@namespace Oqtane.Modules.Admin.Users
|
||||
@using System.Text.RegularExpressions;
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserService UserService
|
||||
@ -20,6 +21,7 @@ else
|
||||
<TabPanel Name="Identity" ResourceKey="Identity">
|
||||
@if (profiles != null)
|
||||
{
|
||||
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
||||
<div class="container">
|
||||
<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>
|
||||
@ -123,13 +125,27 @@ else
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (p.IsRequired)
|
||||
@if (p.Rows == 1)
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
@if (p.IsRequired)
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||
@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>
|
||||
}
|
||||
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>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@ -148,124 +164,129 @@ else
|
||||
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
|
||||
|
||||
@code {
|
||||
private int userid;
|
||||
private string username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
private int photofileid = -1;
|
||||
private File photo = null;
|
||||
private string isdeleted;
|
||||
private string lastlogin;
|
||||
private string lastipaddress;
|
||||
private string _passwordrequirements;
|
||||
private int userid;
|
||||
private string username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
private int photofileid = -1;
|
||||
private File photo = null;
|
||||
private string isdeleted;
|
||||
private string lastlogin;
|
||||
private string lastipaddress;
|
||||
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
private string deletedby;
|
||||
private DateTime? deletedon;
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
private string deletedby;
|
||||
private DateTime? deletedon;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("id"))
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
||||
userid = Int32.Parse(PageState.QueryString["id"]);
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
username = user.Username;
|
||||
email = user.Email;
|
||||
displayname = user.DisplayName;
|
||||
if (user.PhotoFileId != null)
|
||||
{
|
||||
photofileid = user.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
isdeleted = user.IsDeleted.ToString();
|
||||
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
|
||||
lastipaddress = user.LastIPAddress;
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("id"))
|
||||
{
|
||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
||||
userid = Int32.Parse(PageState.QueryString["id"]);
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
username = user.Username;
|
||||
email = user.Email;
|
||||
displayname = user.DisplayName;
|
||||
if (user.PhotoFileId != null)
|
||||
{
|
||||
photofileid = user.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
isdeleted = user.IsDeleted.ToString();
|
||||
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
|
||||
lastipaddress = user.LastIPAddress;
|
||||
|
||||
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
||||
createdby = user.CreatedBy;
|
||||
createdon = user.CreatedOn;
|
||||
modifiedby = user.ModifiedBy;
|
||||
modifiedon = user.ModifiedOn;
|
||||
deletedby = user.DeletedBy;
|
||||
deletedon = user.DeletedOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
||||
createdby = user.CreatedBy;
|
||||
createdon = user.CreatedOn;
|
||||
modifiedby = user.ModifiedBy;
|
||||
modifiedon = user.ModifiedOn;
|
||||
deletedby = user.DeletedBy;
|
||||
deletedon = user.DeletedOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||
{
|
||||
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||
if (value.Contains("]"))
|
||||
{
|
||||
value = value.Substring(value.IndexOf("]") + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private async Task SaveUser()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||
{
|
||||
if (_password == confirm)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = username;
|
||||
user.Password = _password;
|
||||
user.Email = email;
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||
user.PhotoFileId = null;
|
||||
user.PhotoFileId = filemanager.GetFileId();
|
||||
if (user.PhotoFileId == -1)
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
private async Task SaveUser()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty)
|
||||
{
|
||||
if (_password == confirm)
|
||||
{
|
||||
if (ValidateProfiles())
|
||||
{
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = username;
|
||||
user.Password = _password;
|
||||
user.Email = email;
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||
user.PhotoFileId = null;
|
||||
user.PhotoFileId = filemanager.GetFileId();
|
||||
if (user.PhotoFileId == -1)
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
|
||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
||||
|
||||
user = await UserService.UpdateUserAsync(user);
|
||||
if (user != null)
|
||||
{
|
||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
||||
await logger.LogInformation("User Saved {User}", user);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||
}
|
||||
user = await UserService.UpdateUserAsync(user);
|
||||
if (user != null)
|
||||
{
|
||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
||||
await logger.LogInformation("User Saved {User}", user);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -286,19 +307,32 @@ else
|
||||
|
||||
private bool ValidateProfiles()
|
||||
{
|
||||
bool valid = true;
|
||||
foreach (Profile profile in profiles)
|
||||
{
|
||||
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
|
||||
}
|
||||
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
valid = false;
|
||||
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||
{
|
||||
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
|
||||
return false;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(profile.Validation))
|
||||
{
|
||||
Regex regex = new Regex(profile.Validation);
|
||||
bool valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
||||
if (!valid)
|
||||
{
|
||||
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
||||
|
@ -17,27 +17,18 @@ else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Users" Heading="Users" ResourceKey="Users">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-4">
|
||||
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" @bind="@_search" />
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<button type="button" class="btn btn-secondary" @onclick="OnSearch">@SharedLocalizer["Search"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Pager Items="@users" RowClass="align-middle">
|
||||
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
||||
<ActionLink Text="Import Users" Class="btn btn-secondary ms-2" Action="Users" Security="SecurityAccessLevel.Admin" ResourceKey="ImportUsers"/>
|
||||
|
||||
<Pager Items="@users" RowClass="align-middle" SearchProperties="User.Username,User.Email,User.DisplayName">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Username"]</th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@Localizer["LastLoginOn"]</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("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>
|
||||
</Header>
|
||||
<Row>
|
||||
<td>
|
||||
@ -50,11 +41,12 @@ else
|
||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
||||
</td>
|
||||
<td>@context.User.Username</td>
|
||||
<td>@((MarkupString)string.Format("<a href=\"mailto:{0}\">{1}</a>", @context.User.Email, @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>@((context.User.LastLoginOn != DateTime.MinValue) ? string.Format("{0:dd-MMM-yyyy HH:mm:ss}", context.User.LastLoginOn) : "")</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings" Security="SecurityAccessLevel.Admin">
|
||||
<div class="container">
|
||||
<Section Name="User" Heading="User Settings" ResourceKey="UserSettings">
|
||||
@ -259,7 +251,22 @@ else
|
||||
<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="authresponsetype" HelpText="Specify the authorization response type" ResourceKey="AuthResponseType">Authorization Response Type</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="authresponsetype" class="form-select" @bind="@_authresponsetype" required>
|
||||
<option value="code">@Localizer["AuthFlow.Code"]</option>
|
||||
<option value="code id_token">@Localizer["AuthFlow.CodeIdToken"]</option>
|
||||
<option value="code id_token token">@Localizer["AuthFlow.CodeIdTokenToken"]</option>
|
||||
<option value="code token">@Localizer["AuthFlow.CodeToken"]</option>
|
||||
<option value="id_token">@Localizer["AuthFlow.IdToken"]</option>
|
||||
<option value="id_token token">@Localizer["AuthFlow.IdTokenToken"]</option>
|
||||
<option value="token">@Localizer["AuthFlow.Token"]</option>
|
||||
<option value="none">@Localizer["AuthFlow.None"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<select id="pkce" class="form-select" @bind="@_pkce" required>
|
||||
@ -360,144 +367,128 @@ else
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
</TabPanel>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<UserRole> allusers;
|
||||
private List<UserRole> users;
|
||||
private string _search = "";
|
||||
private List<UserRole> users;
|
||||
|
||||
private string _allowregistration;
|
||||
private string _allowsitelogin;
|
||||
private string _twofactor;
|
||||
private string _cookiename;
|
||||
private string _allowregistration;
|
||||
private string _allowsitelogin;
|
||||
private string _twofactor;
|
||||
private string _cookiename;
|
||||
|
||||
private string _minimumlength;
|
||||
private string _uniquecharacters;
|
||||
private string _requiredigit;
|
||||
private string _requireupper;
|
||||
private string _requirelower;
|
||||
private string _requirepunctuation;
|
||||
private string _maximumfailures;
|
||||
private string _lockoutduration;
|
||||
private string _minimumlength;
|
||||
private string _uniquecharacters;
|
||||
private string _requiredigit;
|
||||
private string _requireupper;
|
||||
private string _requirelower;
|
||||
private string _requirepunctuation;
|
||||
private string _maximumfailures;
|
||||
private string _lockoutduration;
|
||||
|
||||
private string _providertype;
|
||||
private string _providername;
|
||||
private string _authority;
|
||||
private string _metadataurl;
|
||||
private string _authorizationurl;
|
||||
private string _tokenurl;
|
||||
private string _userinfourl;
|
||||
private string _clientid;
|
||||
private string _clientsecret;
|
||||
private string _clientsecrettype = "password";
|
||||
private string _toggleclientsecret = string.Empty;
|
||||
private string _scopes;
|
||||
private string _parameters;
|
||||
private string _pkce;
|
||||
private string _redirecturl;
|
||||
private string _identifierclaimtype;
|
||||
private string _emailclaimtype;
|
||||
private string _roleclaimtype;
|
||||
private string _profileclaimtypes;
|
||||
private string _domainfilter;
|
||||
private string _createusers;
|
||||
private string _providertype;
|
||||
private string _providername;
|
||||
private string _authority;
|
||||
private string _metadataurl;
|
||||
private string _authorizationurl;
|
||||
private string _tokenurl;
|
||||
private string _userinfourl;
|
||||
private string _clientid;
|
||||
private string _clientsecret;
|
||||
private string _clientsecrettype = "password";
|
||||
private string _toggleclientsecret = string.Empty;
|
||||
private string _scopes;
|
||||
private string _parameters;
|
||||
private string _pkce;
|
||||
private string _authresponsetype;
|
||||
private string _redirecturl;
|
||||
private string _identifierclaimtype;
|
||||
private string _emailclaimtype;
|
||||
private string _roleclaimtype;
|
||||
private string _profileclaimtypes;
|
||||
private string _domainfilter;
|
||||
private string _createusers;
|
||||
|
||||
private string _secret;
|
||||
private string _secrettype = "password";
|
||||
private string _togglesecret = string.Empty;
|
||||
private string _issuer;
|
||||
private string _audience;
|
||||
private string _lifetime;
|
||||
private string _token;
|
||||
private string _secret;
|
||||
private string _secrettype = "password";
|
||||
private string _togglesecret = string.Empty;
|
||||
private string _issuer;
|
||||
private string _audience;
|
||||
private string _lifetime;
|
||||
private string _token;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||
private bool isSortedAscending;
|
||||
private string activeSortColumn;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadUserSettingsAsync();
|
||||
await LoadUsersAsync(true);
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_allowregistration = PageState.Site.AllowRegistration.ToString();
|
||||
_allowsitelogin = SettingService.GetSetting(settings, "LoginOptions:AllowSiteLogin", "true");
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadUsersAsync(true);
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_twofactor = SettingService.GetSetting(settings, "LoginOptions:TwoFactor", "false");
|
||||
_cookiename = SettingService.GetSetting(settings, "LoginOptions:CookieName", ".AspNetCore.Identity.Application");
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_allowregistration = PageState.Site.AllowRegistration.ToString();
|
||||
_allowsitelogin = SettingService.GetSetting(settings, "LoginOptions:AllowSiteLogin", "true");
|
||||
|
||||
_minimumlength = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredLength", "6");
|
||||
_uniquecharacters = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", "1");
|
||||
_requiredigit = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireDigit", "true");
|
||||
_requireupper = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireUppercase", "true");
|
||||
_requirelower = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireLowercase", "true");
|
||||
_requirepunctuation = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireNonAlphanumeric", "true");
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_twofactor = SettingService.GetSetting(settings, "LoginOptions:TwoFactor", "false");
|
||||
_cookiename = SettingService.GetSetting(settings, "LoginOptions:CookieName", ".AspNetCore.Identity.Application");
|
||||
|
||||
_maximumfailures = SettingService.GetSetting(settings, "IdentityOptions:Lockout:MaxFailedAccessAttempts", "5");
|
||||
_lockoutduration = TimeSpan.Parse(SettingService.GetSetting(settings, "IdentityOptions:Lockout:DefaultLockoutTimeSpan", "00:05:00")).TotalMinutes.ToString();
|
||||
_minimumlength = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredLength", "6");
|
||||
_uniquecharacters = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", "1");
|
||||
_requiredigit = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireDigit", "true");
|
||||
_requireupper = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireUppercase", "true");
|
||||
_requirelower = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireLowercase", "true");
|
||||
_requirepunctuation = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireNonAlphanumeric", "true");
|
||||
|
||||
_providertype = SettingService.GetSetting(settings, "ExternalLogin:ProviderType", "");
|
||||
_providername = SettingService.GetSetting(settings, "ExternalLogin:ProviderName", "");
|
||||
_authority = SettingService.GetSetting(settings, "ExternalLogin:Authority", "");
|
||||
_metadataurl = SettingService.GetSetting(settings, "ExternalLogin:MetadataUrl", "");
|
||||
_authorizationurl = SettingService.GetSetting(settings, "ExternalLogin:AuthorizationUrl", "");
|
||||
_tokenurl = SettingService.GetSetting(settings, "ExternalLogin:TokenUrl", "");
|
||||
_userinfourl = SettingService.GetSetting(settings, "ExternalLogin:UserInfoUrl", "");
|
||||
_clientid = SettingService.GetSetting(settings, "ExternalLogin:ClientId", "");
|
||||
_clientsecret = SettingService.GetSetting(settings, "ExternalLogin:ClientSecret", "");
|
||||
_toggleclientsecret = SharedLocalizer["ShowPassword"];
|
||||
_scopes = SettingService.GetSetting(settings, "ExternalLogin:Scopes", "");
|
||||
_parameters = SettingService.GetSetting(settings, "ExternalLogin:Parameters", "");
|
||||
_pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false");
|
||||
_redirecturl = PageState.Uri.Scheme + "://" + PageState.Alias.Name + "/signin-" + _providertype;
|
||||
_identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "sub");
|
||||
_emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "email");
|
||||
_roleclaimtype = SettingService.GetSetting(settings, "ExternalLogin:RoleClaimType", "");
|
||||
_profileclaimtypes = SettingService.GetSetting(settings, "ExternalLogin:ProfileClaimTypes", "");
|
||||
_domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", "");
|
||||
_createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true");
|
||||
_maximumfailures = SettingService.GetSetting(settings, "IdentityOptions:Lockout:MaxFailedAccessAttempts", "5");
|
||||
_lockoutduration = TimeSpan.Parse(SettingService.GetSetting(settings, "IdentityOptions:Lockout:DefaultLockoutTimeSpan", "00:05:00")).TotalMinutes.ToString();
|
||||
|
||||
_secret = SettingService.GetSetting(settings, "JwtOptions:Secret", "");
|
||||
_togglesecret = SharedLocalizer["ShowPassword"];
|
||||
_issuer = SettingService.GetSetting(settings, "JwtOptions:Issuer", PageState.Uri.Scheme + "://" + PageState.Alias.Name);
|
||||
_audience = SettingService.GetSetting(settings, "JwtOptions:Audience", "");
|
||||
_lifetime = SettingService.GetSetting(settings, "JwtOptions:Lifetime", "20");
|
||||
}
|
||||
}
|
||||
_providertype = SettingService.GetSetting(settings, "ExternalLogin:ProviderType", "");
|
||||
_providername = SettingService.GetSetting(settings, "ExternalLogin:ProviderName", "");
|
||||
_authority = SettingService.GetSetting(settings, "ExternalLogin:Authority", "");
|
||||
_metadataurl = SettingService.GetSetting(settings, "ExternalLogin:MetadataUrl", "");
|
||||
_authorizationurl = SettingService.GetSetting(settings, "ExternalLogin:AuthorizationUrl", "");
|
||||
_tokenurl = SettingService.GetSetting(settings, "ExternalLogin:TokenUrl", "");
|
||||
_userinfourl = SettingService.GetSetting(settings, "ExternalLogin:UserInfoUrl", "");
|
||||
_clientid = SettingService.GetSetting(settings, "ExternalLogin:ClientId", "");
|
||||
_clientsecret = SettingService.GetSetting(settings, "ExternalLogin:ClientSecret", "");
|
||||
_toggleclientsecret = SharedLocalizer["ShowPassword"];
|
||||
_scopes = SettingService.GetSetting(settings, "ExternalLogin:Scopes", "");
|
||||
_parameters = SettingService.GetSetting(settings, "ExternalLogin:Parameters", "");
|
||||
_pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false");
|
||||
_authresponsetype = SettingService.GetSetting(settings, "ExternalLogin:AuthResponseType", "code");
|
||||
_redirecturl = PageState.Uri.Scheme + "://" + PageState.Alias.Name + "/signin-" + _providertype;
|
||||
_identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "sub");
|
||||
_emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "email");
|
||||
_roleclaimtype = SettingService.GetSetting(settings, "ExternalLogin:RoleClaimType", "");
|
||||
_profileclaimtypes = SettingService.GetSetting(settings, "ExternalLogin:ProfileClaimTypes", "");
|
||||
_domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", "");
|
||||
_createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true");
|
||||
|
||||
private async Task LoadUsersAsync(bool load)
|
||||
{
|
||||
if (load)
|
||||
{
|
||||
allusers = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var hosts = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Host);
|
||||
allusers.AddRange(hosts);
|
||||
allusers = allusers.OrderBy(u => u.User.DisplayName).ToList();
|
||||
}
|
||||
}
|
||||
_secret = SettingService.GetSetting(settings, "JwtOptions:Secret", "");
|
||||
_togglesecret = SharedLocalizer["ShowPassword"];
|
||||
_issuer = SettingService.GetSetting(settings, "JwtOptions:Issuer", PageState.Uri.Scheme + "://" + PageState.Alias.Name);
|
||||
_audience = SettingService.GetSetting(settings, "JwtOptions:Audience", "");
|
||||
_lifetime = SettingService.GetSetting(settings, "JwtOptions:Lifetime", "20");
|
||||
}
|
||||
}
|
||||
|
||||
users = allusers;
|
||||
if (!string.IsNullOrEmpty(_search))
|
||||
{
|
||||
users = users.Where(item =>
|
||||
(
|
||||
item.User.Username.Contains(_search, StringComparison.OrdinalIgnoreCase) ||
|
||||
item.User.Email.Contains(_search, StringComparison.OrdinalIgnoreCase) ||
|
||||
item.User.DisplayName.Contains(_search, StringComparison.OrdinalIgnoreCase)
|
||||
)
|
||||
).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSearch()
|
||||
{
|
||||
await UpdateUserSettingsAsync();
|
||||
await LoadUsersAsync(false);
|
||||
private async Task LoadUsersAsync(bool load)
|
||||
{
|
||||
if (load)
|
||||
{
|
||||
users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var hosts = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Host);
|
||||
users.AddRange(hosts);
|
||||
users = users.OrderBy(u => u.User.DisplayName).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteUser(UserRole UserRole)
|
||||
@ -520,21 +511,6 @@ else
|
||||
}
|
||||
}
|
||||
|
||||
private string settingSearch = "AU-search";
|
||||
|
||||
private async Task LoadUserSettingsAsync()
|
||||
{
|
||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||
_search = SettingService.GetSetting(settings, settingSearch, "");
|
||||
}
|
||||
|
||||
private async Task UpdateUserSettingsAsync()
|
||||
{
|
||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||
settings = SettingService.SetSetting(settings, settingSearch, _search);
|
||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
@ -573,6 +549,7 @@ else
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Scopes", _scopes, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Parameters", _parameters, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:PKCE", _pkce, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:AuthResponseType", _authresponsetype, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:IdentifierClaimType", _identifierclaimtype, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:EmailClaimType", _emailclaimtype, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:RoleClaimType", _roleclaimtype, true);
|
||||
@ -654,4 +631,43 @@ else
|
||||
_togglesecret = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
|
||||
private void SortTable(string columnName)
|
||||
{
|
||||
if (columnName != activeSortColumn)
|
||||
{
|
||||
users = users.OrderBy(x => x.User.GetType().GetProperty(columnName)?.GetValue(x.User)).ToList();
|
||||
isSortedAscending = true;
|
||||
activeSortColumn = columnName;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isSortedAscending)
|
||||
{
|
||||
users = users.OrderByDescending(x => x.User.GetType().GetProperty(columnName)?.GetValue(x.User)).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
users = users.OrderBy(x => x.User.GetType().GetProperty(columnName)?.GetValue(x.User)).ToList();
|
||||
}
|
||||
|
||||
isSortedAscending = !isSortedAscending;
|
||||
}
|
||||
}
|
||||
|
||||
private string SetSortIcon(string columnName)
|
||||
{
|
||||
if (activeSortColumn != columnName)
|
||||
{
|
||||
return "app-fas pe-3 ";
|
||||
}
|
||||
if (isSortedAscending)
|
||||
{
|
||||
return "app-fas oi oi-sort-ascending";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "app-fas oi oi-sort-descending";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,13 +34,13 @@ else
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="effectiveDate" HelpText="The date that this role assignment is active" ResourceKey="EffectiveDate">Effective Date: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="effectiveDate" class="form-control" @bind="@effectivedate" />
|
||||
<input type="date" id="effectiveDate" class="form-control" @bind="@effectivedate" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="expiryDate" HelpText="The date that this role assignment expires" ResourceKey="ExpiryDate">Expiry Date: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="expiryDate" class="form-control" @bind="@expirydate" />
|
||||
<input type="date" id="expiryDate" class="form-control" @bind="@expirydate" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -75,8 +75,8 @@ else
|
||||
private string name = string.Empty;
|
||||
private List<Role> roles;
|
||||
private int roleid = -1;
|
||||
private string effectivedate = string.Empty;
|
||||
private string expirydate = string.Empty;
|
||||
private DateTime? effectivedate = null;
|
||||
private DateTime? expirydate = null;
|
||||
private List<UserRole> userroles;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
@ -130,23 +130,8 @@ else
|
||||
var userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault();
|
||||
if (userrole != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(effectivedate))
|
||||
{
|
||||
userrole.EffectiveDate = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
userrole.EffectiveDate = DateTime.Parse(effectivedate);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(expirydate))
|
||||
{
|
||||
userrole.ExpiryDate = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
userrole.ExpiryDate = DateTime.Parse(expirydate);
|
||||
}
|
||||
userrole.EffectiveDate = effectivedate;
|
||||
userrole.ExpiryDate = expirydate;
|
||||
await UserRoleService.UpdateUserRoleAsync(userrole);
|
||||
}
|
||||
else
|
||||
@ -154,25 +139,8 @@ else
|
||||
userrole = new UserRole();
|
||||
userrole.UserId = userid;
|
||||
userrole.RoleId = roleid;
|
||||
|
||||
if (string.IsNullOrEmpty(effectivedate))
|
||||
{
|
||||
userrole.EffectiveDate = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
userrole.EffectiveDate = DateTime.Parse(effectivedate);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(expirydate))
|
||||
{
|
||||
userrole.ExpiryDate = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
userrole.ExpiryDate = DateTime.Parse(expirydate);
|
||||
}
|
||||
|
||||
userrole.EffectiveDate = effectivedate;
|
||||
userrole.ExpiryDate = expirydate;
|
||||
await UserRoleService.AddUserRoleAsync(userrole);
|
||||
}
|
||||
|
||||
|
69
Oqtane.Client/Modules/Admin/Users/Users.razor
Normal file
69
Oqtane.Client/Modules/Admin/Users/Users.razor
Normal file
@ -0,0 +1,69 @@
|
||||
@namespace Oqtane.Modules.Admin.Users
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserService UserService
|
||||
@inject IStringLocalizer<Users> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="importfile" HelpText="Upload or select a tab delimited text file containing user information. The file must be in the Template format specified (Roles can be specified as a comma delimited list)." ResourceKey="ImportFile">Import File:</Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager Id="importfile" @ref="_filemanager" Filter="txt" />
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<select id="notify" class="form-select" @bind="@_notify" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="ImportUsers">@Localizer["Import"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
<a class="btn btn-info" href="/users.txt" target="_new">@Localizer["Template"]</a>
|
||||
|
||||
@code {
|
||||
private FileManager _filemanager;
|
||||
|
||||
public override string Title => "Import Users";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
private string _notify = "True";
|
||||
|
||||
private async Task ImportUsers()
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileid = _filemanager.GetFileId();
|
||||
if (fileid != -1)
|
||||
{
|
||||
ShowProgressIndicator();
|
||||
var results = await UserService.ImportUsersAsync(PageState.Site.SiteId, fileid, bool.Parse(_notify));
|
||||
if (bool.Parse(results["Success"]))
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Message.Import.Success"], results["Users"]), MessageType.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Import.Failure"], MessageType.Error);
|
||||
}
|
||||
HideProgressIndicator();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Import.Validation"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Importing Users {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Import"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
@namespace Oqtane.Modules.Controls
|
||||
@using System.Text.Json
|
||||
@inherits LocalizableComponent
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_visible)
|
||||
{
|
||||
@ -20,7 +21,7 @@
|
||||
{
|
||||
<button type="button" class="@Class" @onclick="Confirm">@((MarkupString)_iconSpan) @Text</button>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" @onclick="DisplayModal">@Localize("Cancel")</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="DisplayModal">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -24,116 +24,135 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _text = string.Empty;
|
||||
private string _parameters = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private List<Permission> _permissions;
|
||||
private bool _editmode = false;
|
||||
private bool _authorized = false;
|
||||
private string _classname = "btn btn-primary";
|
||||
private string _style = string.Empty;
|
||||
private string _iconSpan = string.Empty;
|
||||
private string _text = string.Empty;
|
||||
private int _moduleId = -1;
|
||||
private string _path = string.Empty;
|
||||
private string _parameters = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private List<Permission> _permissions;
|
||||
private bool _editmode = false;
|
||||
private bool _authorized = false;
|
||||
private string _classname = "btn btn-primary";
|
||||
private string _style = string.Empty;
|
||||
private string _iconSpan = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Action { get; set; } // required
|
||||
[Parameter]
|
||||
public string Action { get; set; } // required
|
||||
|
||||
[Parameter]
|
||||
public string Text { get; set; } // optional - defaults to Action if not specified
|
||||
[Parameter]
|
||||
public string Text { get; set; } // optional - defaults to Action if not specified
|
||||
|
||||
[Parameter]
|
||||
public string Parameters { get; set; } // optional - querystring parameters should be in the form of "id=x&name=y"
|
||||
[Parameter]
|
||||
public int ModuleId { get; set; } = -1; // optional - allows the link to target a specific moduleid
|
||||
|
||||
[Parameter]
|
||||
public int ModuleId { get; set; } = -1; // optional - allows the link to target a specific moduleid
|
||||
[Parameter]
|
||||
public string Path { get; set; } = null; // optional - allows the link to target a specific page
|
||||
|
||||
[Parameter]
|
||||
public Action OnClick { get; set; } = null; // optional - executes a method in the calling component
|
||||
[Parameter]
|
||||
public string Parameters { get; set; } // optional - querystring parameters should be in the form of "id=x&name=y"
|
||||
|
||||
[Parameter]
|
||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||
[Parameter]
|
||||
public Action OnClick { get; set; } = null; // optional - executes a method in the calling component
|
||||
|
||||
[Parameter]
|
||||
public string Permissions { get; set; } // deprecated - use PermissionList instead
|
||||
[Parameter]
|
||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||
|
||||
[Parameter]
|
||||
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions
|
||||
[Parameter]
|
||||
public string Permissions { get; set; } // deprecated - use PermissionList instead
|
||||
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; } // optional
|
||||
[Parameter]
|
||||
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions
|
||||
|
||||
[Parameter]
|
||||
public string EditMode { get; set; } // optional - specifies if an authorized user must be in edit mode to see the action - default is false.
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; } // optional
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; } // optional - defaults to primary if not specified
|
||||
[Parameter]
|
||||
public string EditMode { get; set; } // optional - specifies if an authorized user must be in edit mode to see the action - default is false.
|
||||
|
||||
[Parameter]
|
||||
public string Style { get; set; } // optional
|
||||
[Parameter]
|
||||
public string Class { get; set; } // optional - defaults to primary if not specified
|
||||
|
||||
[Parameter]
|
||||
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
||||
[Parameter]
|
||||
public string Style { get; set; } // optional
|
||||
|
||||
[Parameter]
|
||||
public bool IconOnly { get; set; } // optional - specifies only icon in link
|
||||
[Parameter]
|
||||
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
||||
|
||||
[Parameter]
|
||||
public string ReturnUrl { get; set; } // optional - used to set a url to redirect to
|
||||
[Parameter]
|
||||
public bool IconOnly { get; set; } // optional - specifies only icon in link
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Permissions))
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
|
||||
}
|
||||
}
|
||||
[Parameter]
|
||||
public string ReturnUrl { get; set; } // optional - used to set a url to redirect to
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
|
||||
_text = Action;
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
_text = Text;
|
||||
}
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Permissions))
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
|
||||
}
|
||||
}
|
||||
|
||||
if (IconOnly && !string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
_text = string.Empty;
|
||||
}
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
|
||||
if (!string.IsNullOrEmpty(Parameters))
|
||||
{
|
||||
_parameters = Parameters;
|
||||
}
|
||||
_text = Action;
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
_text = Text;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Class))
|
||||
{
|
||||
_classname = Class;
|
||||
}
|
||||
if (IconOnly && !string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
_text = string.Empty;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Style))
|
||||
{
|
||||
_style = Style;
|
||||
}
|
||||
_moduleId = ModuleState.ModuleId;
|
||||
if (ModuleId != -1)
|
||||
{
|
||||
_moduleId = ModuleId;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(EditMode))
|
||||
{
|
||||
_editmode = bool.Parse(EditMode);
|
||||
}
|
||||
_path = PageState.Page.Path;
|
||||
if (Path != null)
|
||||
{
|
||||
_path = Path;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
if (!IconName.Contains(" "))
|
||||
{
|
||||
IconName = "oi oi-" + IconName;
|
||||
}
|
||||
_iconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Parameters))
|
||||
{
|
||||
_parameters = Parameters;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Class))
|
||||
{
|
||||
_classname = Class;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Style))
|
||||
{
|
||||
_style = Style;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(EditMode))
|
||||
{
|
||||
_editmode = bool.Parse(EditMode);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
if (!IconName.Contains(" "))
|
||||
{
|
||||
IconName = "oi oi-" + IconName;
|
||||
}
|
||||
_iconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
||||
}
|
||||
|
||||
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
|
||||
_text = Localize(nameof(Text), _text);
|
||||
_url = (ModuleId == -1) ? EditUrl(Action, _parameters) : EditUrl(ModuleId, Action, _parameters);
|
||||
|
||||
_url = EditUrl(_path, _moduleId, Action, _parameters);
|
||||
if (!string.IsNullOrEmpty(ReturnUrl))
|
||||
{
|
||||
_url += ((_url.Contains("?")) ? "&" : "?") + $"returnurl={WebUtility.UrlEncode(ReturnUrl)}";
|
||||
|
@ -64,12 +64,12 @@
|
||||
|
||||
if (!String.IsNullOrEmpty(ModifiedBy))
|
||||
{
|
||||
_text += $" {Localizer["by"]} <b>{ModifiedBy}</b>";
|
||||
_text += $" {Localizer["By"]} <b>{ModifiedBy}</b>";
|
||||
}
|
||||
|
||||
if (ModifiedOn != null)
|
||||
{
|
||||
_text += $" {Localizer["on"]} <b>{ModifiedOn.Value.ToString(DateTimeFormat)}</b>";
|
||||
_text += $" {Localizer["On"]} <b>{ModifiedOn.Value.ToString(DateTimeFormat)}</b>";
|
||||
}
|
||||
|
||||
_text += "</p>";
|
||||
|
@ -2,7 +2,7 @@
|
||||
@inherits LocalizableComponent
|
||||
|
||||
<div class="app-autocomplete">
|
||||
<input class="form-control" value="@Value" @oninput="OnInput" @onkeyup="OnKeyUp" placeholder="@Placeholder" autocomplete="off" />
|
||||
<input class="form-control" value="@Value" @oninput="OnInput" @onkeyup="OnKeyUp" placeholder="@Placeholder" autocomplete="off" @attributes="InputAttributes" />
|
||||
@if (_results != null)
|
||||
{
|
||||
<select class="form-select" style="position: relative;" value="@Value" size="@Rows" @onkeyup="OnKeyUp" @onchange="(e => OnChange(e))">
|
||||
@ -29,27 +29,48 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
Dictionary<string, string> _results;
|
||||
Dictionary<string, string> _results;
|
||||
Dictionary<string, object> InputAttributes { get; set; } = new();
|
||||
|
||||
[Parameter]
|
||||
public Func<string, Task<Dictionary<string, string>>> OnSearch { get; set; } // required - an async delegate method which accepts a filter string parameter and returns a dictionary
|
||||
[Parameter]
|
||||
public Func<string, Task<Dictionary<string, string>>> OnSearch { get; set; } // required - an async delegate method which accepts a filter string parameter and returns a dictionary
|
||||
|
||||
[Parameter]
|
||||
public int Characters { get; set; } = 3; // optional - number of characters before search is initiated
|
||||
[Parameter]
|
||||
public int Characters { get; set; } = 3; // optional - number of characters before search is initiated
|
||||
|
||||
[Parameter]
|
||||
public int Rows { get; set; } = 3; // optional - number of result rows to display
|
||||
[Parameter]
|
||||
public int Rows { get; set; } = 3; // optional - number of result rows to display
|
||||
|
||||
[Parameter]
|
||||
public string Placeholder { get; set; } // optional - placeholder input text
|
||||
[Parameter]
|
||||
public string Placeholder { get; set; } // optional - placeholder input text
|
||||
|
||||
[Parameter]
|
||||
public string Value { get; set; } // value of item selected
|
||||
[Parameter]
|
||||
public string Value { get; set; } // value of item selected
|
||||
|
||||
[Parameter]
|
||||
public string Key { get; set; } // key of item selected
|
||||
[Parameter]
|
||||
public string Key { get; set; } // key of item selected
|
||||
|
||||
private async Task OnInput(ChangeEventArgs e)
|
||||
[Parameter]
|
||||
public bool Required { get; set; } // optional - if the item is required
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (Required)
|
||||
{
|
||||
if (!InputAttributes.ContainsKey(nameof(Required)))
|
||||
{
|
||||
InputAttributes.Add(nameof(Required), true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (InputAttributes.ContainsKey(nameof(Required)))
|
||||
{
|
||||
InputAttributes.Remove(nameof(Required));
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task OnInput(ChangeEventArgs e)
|
||||
{
|
||||
Value = e.Value?.ToString();
|
||||
if (Value?.Length >= Characters)
|
||||
|
@ -40,6 +40,13 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetFileId() != -1 && !UploadMultiple)
|
||||
{
|
||||
<input class="form-control" @bind="@_file.Name" disabled />
|
||||
}
|
||||
}
|
||||
@if (ShowUpload && _haseditpermission)
|
||||
{
|
||||
<div class="row">
|
||||
@ -55,16 +62,26 @@
|
||||
</div>
|
||||
<div class="col mt-2 text-end">
|
||||
<button type="button" class="btn btn-success" @onclick="UploadFiles">@SharedLocalizer["Upload"]</button>
|
||||
@if (ShowFiles && GetFileId() != -1)
|
||||
@if (GetFileId() != -1 && !UploadMultiple)
|
||||
{
|
||||
<button type="button" class="btn btn-danger mx-1" @onclick="DeleteFile">@SharedLocalizer["Delete"]</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mt-1"><span id="@_progressinfoid" style="display: none;"></span></div>
|
||||
<div class="col text-center mt-1"><progress id="@_progressbarid" class="mt-1" style="display: none;"></progress></div>
|
||||
</div>
|
||||
@if (ShowProgress)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col mt-1"><span id="@_progressinfoid" style="display: none;"></span></div>
|
||||
<div class="col mt-1"><progress id="@_progressbarid" class="mt-1" style="display: none;"></progress></div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_uploading)
|
||||
{
|
||||
<div class="app-progress-indicator"></div>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@ -100,6 +117,7 @@
|
||||
private string _guid;
|
||||
private string _message = string.Empty;
|
||||
private MessageType _messagetype;
|
||||
private bool _uploading = false;
|
||||
|
||||
[Parameter]
|
||||
public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility
|
||||
@ -128,6 +146,9 @@
|
||||
[Parameter]
|
||||
public bool ShowImage { get; set; } = true; // optional - for indicating whether an image thumbnail should be displayed - default is true
|
||||
|
||||
[Parameter]
|
||||
public bool ShowProgress { get; set; } = true; // optional - for indicating whether progress info should be displayed during upload - default is true
|
||||
|
||||
[Parameter]
|
||||
public bool ShowSuccess { get; set; } = false; // optional - for indicating whether a success message should be displayed upon successful upload - default is false
|
||||
|
||||
@ -143,7 +164,16 @@
|
||||
[Parameter]
|
||||
public EventCallback<int> OnDelete { get; set; } // optional - executes a method in the calling component when a file is deleted
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
// create unique id for component
|
||||
_guid = Guid.NewGuid().ToString("N");
|
||||
_fileinputid = "FileInput_" + _guid;
|
||||
_progressinfoid = "ProgressInfo_" + _guid;
|
||||
_progressbarid = "ProgressBar_" + _guid;
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
// packages folder is a framework folder for uploading installable nuget packages
|
||||
if (Folder == Constants.PackagesFolder)
|
||||
@ -154,13 +184,6 @@
|
||||
ShowSuccess = true;
|
||||
}
|
||||
|
||||
if (!ShowFiles)
|
||||
{
|
||||
ShowImage = false;
|
||||
}
|
||||
|
||||
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
||||
|
||||
if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder)
|
||||
{
|
||||
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
||||
@ -176,13 +199,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (ShowFolders)
|
||||
{
|
||||
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FolderId != -1)
|
||||
{
|
||||
var folder = await FolderService.GetFolderAsync(FolderId);
|
||||
if (folder != null)
|
||||
{
|
||||
_folders = new List<Folder> { folder };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FileId != -1)
|
||||
{
|
||||
File file = await FileService.GetFileAsync(FileId);
|
||||
if (file != null)
|
||||
{
|
||||
FolderId = file.FolderId;
|
||||
await OnSelect.InvokeAsync(FileId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -201,12 +239,6 @@
|
||||
|
||||
await GetFiles();
|
||||
|
||||
// create unique id for component
|
||||
_guid = Guid.NewGuid().ToString("N");
|
||||
_fileinputid = "FileInput_" + _guid;
|
||||
_progressinfoid = "ProgressInfo_" + _guid;
|
||||
_progressbarid = "ProgressBar_" + _guid;
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
@ -224,7 +256,14 @@
|
||||
if (folder != null)
|
||||
{
|
||||
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.PermissionList);
|
||||
_files = await FileService.GetFilesAsync(FolderId);
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Browse, folder.PermissionList))
|
||||
{
|
||||
_files = await FileService.GetFilesAsync(FolderId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_files = new List<File>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -270,13 +309,10 @@
|
||||
{
|
||||
_message = string.Empty;
|
||||
FileId = int.Parse((string)e.Value);
|
||||
if (FileId != -1)
|
||||
{
|
||||
await OnSelect.InvokeAsync(FileId);
|
||||
}
|
||||
|
||||
await SetImage();
|
||||
await OnSelect.InvokeAsync(FileId);
|
||||
StateHasChanged();
|
||||
|
||||
}
|
||||
|
||||
private async Task SetImage()
|
||||
@ -312,7 +348,8 @@
|
||||
string restricted = "";
|
||||
foreach (var upload in uploads)
|
||||
{
|
||||
var extension = (upload.LastIndexOf(".") != -1) ? upload.Substring(upload.LastIndexOf(".") + 1) : "";
|
||||
var filename = upload.Split(':')[0];
|
||||
var extension = (filename.LastIndexOf(".") != -1) ? filename.Substring(filename.LastIndexOf(".") + 1) : "";
|
||||
if (!Constants.UploadableFiles.Split(',').Contains(extension.ToLower()))
|
||||
{
|
||||
restricted += (restricted == "" ? "" : ",") + extension;
|
||||
@ -320,6 +357,12 @@
|
||||
}
|
||||
if (restricted == "")
|
||||
{
|
||||
if (!ShowProgress)
|
||||
{
|
||||
_uploading = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// upload the files
|
||||
@ -327,32 +370,56 @@
|
||||
var folder = (Folder == Constants.PackagesFolder) ? Folder : FolderId.ToString();
|
||||
await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken);
|
||||
|
||||
// uploading is asynchronous so we need to wait for the uploads to complete
|
||||
// note that this will only wait a maximum of 15 seconds which may not be long enough for very large file uploads
|
||||
bool success = false;
|
||||
int attempts = 0;
|
||||
while (attempts < 5 && !success)
|
||||
// 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)
|
||||
{
|
||||
attempts += 1;
|
||||
Thread.Sleep(1000 * attempts); // progressive retry
|
||||
success = false;
|
||||
var filename = uploads[upload].Split(':')[0];
|
||||
var size = Int64.Parse(uploads[upload].Split(':')[1]);
|
||||
var maxattempts = (int)Math.Ceiling(size / 500000.0) + 4; // 30 MB takes 1 minute at 5 Mbps (min 5 attempts)
|
||||
|
||||
success = true;
|
||||
List<File> files = await FileService.GetFilesAsync(folder);
|
||||
if (files.Count > 0)
|
||||
int attempts = 0;
|
||||
while (attempts < maxattempts && !success)
|
||||
{
|
||||
foreach (string upload in uploads)
|
||||
attempts += 1;
|
||||
Thread.Sleep(1000);
|
||||
|
||||
if (Folder == Constants.PackagesFolder)
|
||||
{
|
||||
if (!files.Exists(item => item.Name == upload))
|
||||
var files = await FileService.GetFilesAsync(folder);
|
||||
if (files != null && files.Any(item => item.Name == filename))
|
||||
{
|
||||
success = false;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var file = await FileService.GetFileAsync(int.Parse(folder), filename);
|
||||
if (file != null)
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
upload++;
|
||||
}
|
||||
}
|
||||
|
||||
// reset progress indicators
|
||||
await interop.SetElementAttribute(_guid + "ProgressInfo", "style", "display: none;");
|
||||
await interop.SetElementAttribute(_guid + "ProgressBar", "style", "display: none;");
|
||||
if (ShowProgress)
|
||||
{
|
||||
await interop.SetElementAttribute(_progressinfoid, "style", "display: none;");
|
||||
await interop.SetElementAttribute(_progressbarid, "style", "display: none;");
|
||||
}
|
||||
else
|
||||
{
|
||||
_uploading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
@ -377,53 +444,60 @@
|
||||
else
|
||||
{
|
||||
// set FileId to first file in upload collection
|
||||
await GetFiles();
|
||||
var file = _files.Where(item => item.Name == uploads[0]).FirstOrDefault();
|
||||
var file = await FileService.GetFileAsync(int.Parse(folder), uploads[0].Split(":")[0]);
|
||||
if (file != null)
|
||||
{
|
||||
FileId = file.FileId;
|
||||
await SetImage();
|
||||
await OnSelect.InvokeAsync(FileId);
|
||||
await OnUpload.InvokeAsync(FileId);
|
||||
}
|
||||
await GetFiles();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "File Upload Failed {Error}", ex.Message);
|
||||
_message = Localizer["Error.File.Upload"];
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = string.Format(Localizer["Message.File.Restricted"], restricted);
|
||||
_messagetype = MessageType.Warning;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = Localizer["Message.File.NotSelected"];
|
||||
_messagetype = MessageType.Warning;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "File Upload Failed {Error}", ex.Message);
|
||||
_message = Localizer["Error.File.Upload"];
|
||||
_messagetype = MessageType.Error;
|
||||
_uploading = false;
|
||||
}
|
||||
|
||||
private async Task DeleteFile()
|
||||
{
|
||||
_message = string.Empty;
|
||||
try
|
||||
{
|
||||
await FileService.DeleteFileAsync(FileId);
|
||||
await logger.LogInformation("File Deleted {File}", FileId);
|
||||
await OnDelete.InvokeAsync(FileId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = string.Format(Localizer["Message.File.Restricted"], restricted);
|
||||
_messagetype = MessageType.Warning;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = Localizer["Message.File.NotSelected"];
|
||||
_messagetype = MessageType.Warning;
|
||||
}
|
||||
}
|
||||
|
||||
_message = Localizer["Success.File.Delete"];
|
||||
_messagetype = MessageType.Success;
|
||||
private async Task DeleteFile()
|
||||
{
|
||||
_message = string.Empty;
|
||||
try
|
||||
{
|
||||
await FileService.DeleteFileAsync(FileId);
|
||||
await logger.LogInformation("File Deleted {File}", FileId);
|
||||
await OnDelete.InvokeAsync(FileId);
|
||||
|
||||
if (ShowSuccess)
|
||||
{
|
||||
_message = Localizer["Success.File.Delete"];
|
||||
_messagetype = MessageType.Success;
|
||||
}
|
||||
|
||||
await GetFiles();
|
||||
FileId = -1;
|
||||
await SetImage();
|
||||
StateHasChanged();
|
||||
await OnSelect.InvokeAsync(FileId);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
50
Oqtane.Client/Modules/Controls/InputList.razor
Normal file
50
Oqtane.Client/Modules/Controls/InputList.razor
Normal file
@ -0,0 +1,50 @@
|
||||
@namespace Oqtane.Modules.Controls
|
||||
@inherits LocalizableComponent
|
||||
|
||||
<input type="text" value="@Value" list="@_id" class="form-control" @onchange="(e => OnChange(e))" />
|
||||
<datalist id="@_id" value="@Value">
|
||||
@foreach(var kvp in DataList)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(kvp.Value))
|
||||
{
|
||||
<option value="@kvp.Key">@Localize(kvp.Value, kvp.Value)</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@kvp.Key">@Localize(kvp.Key, kvp.Key)</option>
|
||||
}
|
||||
}
|
||||
</datalist>
|
||||
|
||||
@code {
|
||||
private string _id;
|
||||
|
||||
[Parameter]
|
||||
public string Value { get; set; }
|
||||
|
||||
[EditorRequired]
|
||||
[Parameter]
|
||||
public Dictionary<string, string> DataList { get; set; }
|
||||
|
||||
[EditorRequired]
|
||||
[Parameter]
|
||||
public EventCallback<string> ValueChanged { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
// create unique id for component
|
||||
_id = "DataList_" + Guid.NewGuid().ToString("N");
|
||||
}
|
||||
|
||||
protected void OnChange(ChangeEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Value.ToString()))
|
||||
{
|
||||
Value = e.Value.ToString();
|
||||
if (ValueChanged.HasDelegate)
|
||||
{
|
||||
ValueChanged.InvokeAsync(Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,20 @@
|
||||
@namespace Oqtane.Modules.Controls
|
||||
@inherits ModuleControlBase
|
||||
@inject IStringLocalizerFactory LocalizerFactory
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
@typeparam TableItem
|
||||
|
||||
@if (ItemList != null)
|
||||
{
|
||||
@if (!string.IsNullOrEmpty(SearchProperties))
|
||||
{
|
||||
<div class="input-group my-3">
|
||||
<input id="search" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" />
|
||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||
{
|
||||
<ul class="pagination justify-content-center my-2">
|
||||
@ -175,6 +185,9 @@
|
||||
private int _startPage = 0;
|
||||
private int _endPage = 0;
|
||||
private int _columns = 0;
|
||||
private string _search = "";
|
||||
|
||||
private IEnumerable<TableItem> AllItems;
|
||||
|
||||
[Parameter]
|
||||
public string Format { get; set; } // Table or Grid
|
||||
@ -221,6 +234,9 @@
|
||||
[Parameter]
|
||||
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
|
||||
|
||||
[Parameter]
|
||||
public string SearchProperties { get; set; } // comma delimited list of property names to include in search
|
||||
|
||||
private IEnumerable<TableItem> ItemList { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
@ -276,6 +292,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(SearchProperties))
|
||||
{
|
||||
AllItems = Items; // only used in search
|
||||
if (!string.IsNullOrEmpty(_search))
|
||||
{
|
||||
Search();
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(PageSize))
|
||||
{
|
||||
_maxItems = int.Parse(PageSize);
|
||||
@ -323,10 +348,10 @@
|
||||
{
|
||||
_endPage = _pages;
|
||||
}
|
||||
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
|
||||
StateHasChanged();
|
||||
OnPageChange?.Invoke(_page);
|
||||
}
|
||||
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
|
||||
StateHasChanged();
|
||||
OnPageChange?.Invoke(_page);
|
||||
}
|
||||
|
||||
public void UpdateList(int page)
|
||||
{
|
||||
@ -369,4 +394,75 @@
|
||||
|
||||
UpdateList(_page);
|
||||
}
|
||||
|
||||
public void Search()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_search))
|
||||
{
|
||||
Items = AllItems.Where(item =>
|
||||
{
|
||||
var values = SearchProperties.Split(',')
|
||||
.Select(itemType => GetPropertyValue(item, itemType))
|
||||
.Where(value => value != null)
|
||||
.Select(value => value.ToString().ToLower());
|
||||
|
||||
return values.Any(value => value.Contains(_search.ToLower()));
|
||||
}).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
Items = AllItems;
|
||||
}
|
||||
_pages = (int)Math.Ceiling(Items.Count() / (decimal)_maxItems);
|
||||
UpdateList(1);
|
||||
}
|
||||
|
||||
private object GetPropertyValue(object obj, string propertyName)
|
||||
{
|
||||
var index = propertyName.IndexOf(".");
|
||||
if (index != -1)
|
||||
{
|
||||
var propertyInfo = obj.GetType().GetProperty(propertyName.Substring(0, index));
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
return GetPropertyValue(propertyInfo.GetValue(obj), propertyName.Substring(index + 1));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var propertyInfo = obj.GetType().GetProperty(propertyName);
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
return propertyInfo.GetValue(obj);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_search = "";
|
||||
Items = AllItems;
|
||||
_pages = (int)Math.Ceiling(Items.Count() / (decimal)_maxItems);
|
||||
UpdateList(1);
|
||||
}
|
||||
|
||||
private string FormatSearchProperties()
|
||||
{
|
||||
var properties = new List<string>();
|
||||
foreach (var property in SearchProperties.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var index = property.LastIndexOf(".");
|
||||
if (index != -1)
|
||||
{
|
||||
properties.Add(property.Substring(index + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
properties.Add(property);
|
||||
}
|
||||
}
|
||||
return string.Join(",", properties);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<div class="row" style="margin-bottom: 50px;">
|
||||
<div class="col">
|
||||
<TabStrip>
|
||||
<TabPanel Name="Rich" Heading="Rich Text Editor">
|
||||
<TabPanel Name="Rich" Heading="Rich Text Editor" ResourceKey="RichTextEditor">
|
||||
@if (_richfilemanager)
|
||||
{
|
||||
<FileManager @ref="_fileManager" Filter="@Constants.ImageFiles" />
|
||||
|
@ -17,7 +17,10 @@
|
||||
<hr class="app-rule" />
|
||||
</div>
|
||||
<div class="collapse @_show" id="@Name">
|
||||
@ChildContent
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
@ -26,7 +29,7 @@
|
||||
private string _show = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
public RenderFragment ChildContent { get; set; } = null;
|
||||
|
||||
[Parameter]
|
||||
public string Name { get; set; } // required - the name of the section
|
||||
@ -37,19 +40,12 @@
|
||||
[Parameter]
|
||||
public string Expanded { get; set; } // optional - will default to false if not provided
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_heading = (!string.IsNullOrEmpty(Heading)) ? Heading : Name;
|
||||
_expanded = (!string.IsNullOrEmpty(Expanded)) ? Expanded : "false";
|
||||
if (_expanded == "true") { _show = "show"; }
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
base.OnParametersSet(); // must be included to call method in LocalizableComponent
|
||||
|
||||
_heading = !string.IsNullOrEmpty(Heading)
|
||||
? Localize(nameof(Heading), Heading)
|
||||
: Localize(nameof(Name), Name);
|
||||
_heading = !string.IsNullOrEmpty(Heading) ? Localize(nameof(Heading), Heading) : Localize(nameof(Name), Name);
|
||||
_expanded = (!string.IsNullOrEmpty(Expanded)) ? Expanded.ToLower() : "false";
|
||||
if (_expanded == "true") { _show = "show"; }
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
@foreach (TabPanel tabPanel in _tabPanels)
|
||||
{
|
||||
<li class="nav-item" @key="tabPanel.Name">
|
||||
@if (tabPanel.Name == ActiveTab)
|
||||
@if (tabPanel.Name.ToLower() == ActiveTab.ToLower())
|
||||
{
|
||||
<a class="nav-link active" data-bs-toggle="tab" href="#@(Id + tabPanel.Name)" role="tab" @onclick:preventDefault="true">
|
||||
@tabPanel.DisplayHeading()
|
||||
|
@ -53,7 +53,6 @@
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.bubble.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
|
||||
};
|
||||
|
@ -15,11 +15,6 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
||||
};
|
||||
|
||||
private string content = "";
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
|
@ -1,5 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Modules.HtmlText
|
||||
{
|
||||
@ -13,7 +15,11 @@ namespace Oqtane.Modules.HtmlText
|
||||
Version = "1.0.1",
|
||||
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
|
||||
ReleaseVersions = "1.0.0,1.0.1",
|
||||
SettingsType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"
|
||||
SettingsType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client",
|
||||
Resources = new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Module.css" }
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ using Oqtane.UI;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.JSInterop;
|
||||
using System.Linq;
|
||||
using System.Dynamic;
|
||||
|
||||
namespace Oqtane.Modules
|
||||
{
|
||||
@ -70,17 +71,33 @@ namespace Oqtane.Modules
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
||||
List<Resource> resources = null;
|
||||
var type = GetType();
|
||||
if (type.BaseType == typeof(ModuleBase))
|
||||
{
|
||||
if (PageState.Page.Resources != null)
|
||||
{
|
||||
resources = PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Script && item.Level != ResourceLevel.Site && item.Namespace == type.Namespace).ToList();
|
||||
}
|
||||
}
|
||||
else // modulecontrolbase
|
||||
{
|
||||
if (Resources != null)
|
||||
{
|
||||
resources = Resources.Where(item => item.ResourceType == ResourceType.Script).ToList();
|
||||
}
|
||||
}
|
||||
if (resources != null &&resources.Any())
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
var scripts = new List<object>();
|
||||
var inline = 0;
|
||||
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
||||
foreach (Resource resource in resources)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(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 });
|
||||
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module, location = resource.Location.ToString().ToLower() });
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -104,6 +121,7 @@ namespace Oqtane.Modules
|
||||
}
|
||||
|
||||
// url methods
|
||||
|
||||
public string NavigateUrl()
|
||||
{
|
||||
return NavigateUrl(PageState.Page.Path);
|
||||
@ -263,16 +281,47 @@ namespace Oqtane.Modules
|
||||
|
||||
public void SetModuleTitle(string title)
|
||||
{
|
||||
var obj = new { PageModuleId = ModuleState.PageModuleId, Title = title };
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.PageModuleId = ModuleState.PageModuleId;
|
||||
obj.Title = title;
|
||||
SiteState.Properties.ModuleTitle = obj;
|
||||
}
|
||||
|
||||
public void SetModuleVisibility(bool visible)
|
||||
{
|
||||
var obj = new { PageModuleId = ModuleState.PageModuleId, Visible = visible };
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.PageModuleId = ModuleState.PageModuleId;
|
||||
obj.Visible = visible;
|
||||
SiteState.Properties.ModuleVisibility = obj;
|
||||
}
|
||||
|
||||
public void SetPageTitle(string title)
|
||||
{
|
||||
SiteState.Properties.PageTitle = title;
|
||||
}
|
||||
|
||||
// note - only supports links and meta tags - not scripts
|
||||
public void AddHeadContent(string content)
|
||||
{
|
||||
SiteState.AppendHeadContent(content);
|
||||
}
|
||||
|
||||
public void AddScript(Resource resource)
|
||||
{
|
||||
resource.ResourceType = ResourceType.Script;
|
||||
if (Resources == null) Resources = new List<Resource>();
|
||||
if (!Resources.Any(item => (!string.IsNullOrEmpty(resource.Url) && item.Url == resource.Url) || (!string.IsNullOrEmpty(resource.Content) && item.Content == resource.Content)))
|
||||
{
|
||||
Resources.Add(resource);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ScrollToPageTop()
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
|
||||
// logging methods
|
||||
public async Task Log(Alias alias, LogLevel level, string function, Exception exception, string message, params object[] args)
|
||||
{
|
||||
|
@ -1,19 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>3.4.3</Version>
|
||||
<Version>4.0.6</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
<Description>Modular Application Framework for Blazor and MAUI</Description>
|
||||
<Description>CMS and Application Framework for Blazor and .NET MAUI</Description>
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
@ -22,13 +21,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.3" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="6.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.5" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="6.0.3" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,22 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.JSInterop;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Modules;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.UI;
|
||||
|
||||
namespace Oqtane.Client
|
||||
@ -66,6 +69,14 @@ namespace Oqtane.Client
|
||||
|
||||
private static async Task LoadClientAssemblies(HttpClient http, IServiceProvider serviceProvider)
|
||||
{
|
||||
// get alias
|
||||
var navigationManager = serviceProvider.GetRequiredService<NavigationManager>();
|
||||
var urlpath = GetUrlPath(navigationManager.Uri);
|
||||
var json = await http.GetStringAsync($"api/Installation/installed/?path={WebUtility.UrlEncode(urlpath)}");
|
||||
var installation = JsonSerializer.Deserialize<Installation>(json, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
||||
urlpath = installation.Alias.Path;
|
||||
urlpath = (!string.IsNullOrEmpty(urlpath)) ? urlpath + "/" : urlpath;
|
||||
|
||||
var dlls = new Dictionary<string, byte[]>();
|
||||
var pdbs = new Dictionary<string, byte[]>();
|
||||
var list = new List<string>();
|
||||
@ -77,7 +88,7 @@ namespace Oqtane.Client
|
||||
if (files.Count() != 0)
|
||||
{
|
||||
// get list of assemblies from server
|
||||
var json = await http.GetStringAsync("/api/Installation/list");
|
||||
json = await http.GetStringAsync($"{urlpath}api/Installation/list");
|
||||
var assemblies = JsonSerializer.Deserialize<List<string>>(json);
|
||||
|
||||
// determine which assemblies need to be downloaded
|
||||
@ -139,7 +150,7 @@ namespace Oqtane.Client
|
||||
if (list.Count != 0)
|
||||
{
|
||||
// get assemblies from server and load into client app domain
|
||||
var zip = await http.GetByteArrayAsync($"/api/Installation/load?list=" + string.Join(",", list));
|
||||
var zip = await http.GetByteArrayAsync($"{urlpath}api/Installation/load?list=" + string.Join(",", list));
|
||||
|
||||
// asemblies and debug symbols are packaged in a zip file
|
||||
using (ZipArchive archive = new ZipArchive(new MemoryStream(zip)))
|
||||
@ -255,5 +266,10 @@ namespace Oqtane.Client
|
||||
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
|
||||
}
|
||||
|
||||
private static string GetUrlPath(string url)
|
||||
{
|
||||
return new Uri(url).AbsolutePath.Substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
789
Oqtane.Client/Resources/IconResources.resx
Normal file
789
Oqtane.Client/Resources/IconResources.resx
Normal file
@ -0,0 +1,789 @@
|
||||
<?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="Icon.AccountLogin" xml:space="preserve">
|
||||
<value>Account Login</value>
|
||||
</data>
|
||||
<data name="Icon.AccountLogout" xml:space="preserve">
|
||||
<value>Account Logout</value>
|
||||
</data>
|
||||
<data name="Icon.ActionRedo" xml:space="preserve">
|
||||
<value>Action Redo</value>
|
||||
</data>
|
||||
<data name="Icon.ActionUndo" xml:space="preserve">
|
||||
<value>Action Undo</value>
|
||||
</data>
|
||||
<data name="Icon.AlignCenter" xml:space="preserve">
|
||||
<value>Align Center</value>
|
||||
</data>
|
||||
<data name="Icon.AlignLeft" xml:space="preserve">
|
||||
<value>Align Left</value>
|
||||
</data>
|
||||
<data name="Icon.AlignRight" xml:space="preserve">
|
||||
<value>Align Right</value>
|
||||
</data>
|
||||
<data name="Icon.Aperture" xml:space="preserve">
|
||||
<value>Aperture</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowBottom" xml:space="preserve">
|
||||
<value>Arrow Bottom</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowCircleBottom" xml:space="preserve">
|
||||
<value>Arrow Circle Bottom</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowCircleLeft" xml:space="preserve">
|
||||
<value>Arrow Circle Left</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowCircleRight" xml:space="preserve">
|
||||
<value>Arrow Circle Right</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowCircleTop" xml:space="preserve">
|
||||
<value>Arrow Circle Top</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowLeft" xml:space="preserve">
|
||||
<value>Arrow Left</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowRight" xml:space="preserve">
|
||||
<value>Arrow Right</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowThickBottom" xml:space="preserve">
|
||||
<value>Arrow Thick Bottom</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowThickLeft" xml:space="preserve">
|
||||
<value>Arrow Thick Left</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowThickRight" xml:space="preserve">
|
||||
<value>Arrow Thick Right</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowThickTop" xml:space="preserve">
|
||||
<value>Arrow Thick Top</value>
|
||||
</data>
|
||||
<data name="Icon.ArrowTop" xml:space="preserve">
|
||||
<value>Arrow Top</value>
|
||||
</data>
|
||||
<data name="Icon.AudioSpectrum" xml:space="preserve">
|
||||
<value>Audio Spectrum</value>
|
||||
</data>
|
||||
<data name="Icon.Audio" xml:space="preserve">
|
||||
<value>Audio</value>
|
||||
</data>
|
||||
<data name="Icon.Badge" xml:space="preserve">
|
||||
<value>Badge</value>
|
||||
</data>
|
||||
<data name="Icon.Ban" xml:space="preserve">
|
||||
<value>Ban</value>
|
||||
</data>
|
||||
<data name="Icon.BarChart" xml:space="preserve">
|
||||
<value>Bar Chart</value>
|
||||
</data>
|
||||
<data name="Icon.Basket" xml:space="preserve">
|
||||
<value>Basket</value>
|
||||
</data>
|
||||
<data name="Icon.BatteryEmpty" xml:space="preserve">
|
||||
<value>Battery Empty</value>
|
||||
</data>
|
||||
<data name="Icon.BatteryFull" xml:space="preserve">
|
||||
<value>Battery Full</value>
|
||||
</data>
|
||||
<data name="Icon.Beaker" xml:space="preserve">
|
||||
<value>Beaker</value>
|
||||
</data>
|
||||
<data name="Icon.Bell" xml:space="preserve">
|
||||
<value>Bell</value>
|
||||
</data>
|
||||
<data name="Icon.Bluetooth" xml:space="preserve">
|
||||
<value>Bluetooth</value>
|
||||
</data>
|
||||
<data name="Icon.Bold" xml:space="preserve">
|
||||
<value>Bold</value>
|
||||
</data>
|
||||
<data name="Icon.Bolt" xml:space="preserve">
|
||||
<value>Bolt</value>
|
||||
</data>
|
||||
<data name="Icon.Book" xml:space="preserve">
|
||||
<value>Book</value>
|
||||
</data>
|
||||
<data name="Icon.Bookmark" xml:space="preserve">
|
||||
<value>Bookmark</value>
|
||||
</data>
|
||||
<data name="Icon.Box" xml:space="preserve">
|
||||
<value>Box</value>
|
||||
</data>
|
||||
<data name="Icon.Briefcase" xml:space="preserve">
|
||||
<value>Briefcase</value>
|
||||
</data>
|
||||
<data name="Icon.BritishPound" xml:space="preserve">
|
||||
<value>British Pound</value>
|
||||
</data>
|
||||
<data name="Icon.Browser" xml:space="preserve">
|
||||
<value>Browser</value>
|
||||
</data>
|
||||
<data name="Icon.Brush" xml:space="preserve">
|
||||
<value>Brush</value>
|
||||
</data>
|
||||
<data name="Icon.Bug" xml:space="preserve">
|
||||
<value>Bug</value>
|
||||
</data>
|
||||
<data name="Icon.Bullhorn" xml:space="preserve">
|
||||
<value>Bullhorn</value>
|
||||
</data>
|
||||
<data name="Icon.Calculator" xml:space="preserve">
|
||||
<value>Calculator</value>
|
||||
</data>
|
||||
<data name="Icon.Calendar" xml:space="preserve">
|
||||
<value>Calendar</value>
|
||||
</data>
|
||||
<data name="Icon.CameraSlr" xml:space="preserve">
|
||||
<value>Camera Slr</value>
|
||||
</data>
|
||||
<data name="Icon.CaretBottom" xml:space="preserve">
|
||||
<value>Caret Bottom</value>
|
||||
</data>
|
||||
<data name="Icon.CaretLeft" xml:space="preserve">
|
||||
<value>Caret Left</value>
|
||||
</data>
|
||||
<data name="Icon.CaretRight" xml:space="preserve">
|
||||
<value>Caret Right</value>
|
||||
</data>
|
||||
<data name="Icon.CaretTop" xml:space="preserve">
|
||||
<value>Caret Top</value>
|
||||
</data>
|
||||
<data name="Icon.Cart" xml:space="preserve">
|
||||
<value>Cart</value>
|
||||
</data>
|
||||
<data name="Icon.Chat" xml:space="preserve">
|
||||
<value>Chat</value>
|
||||
</data>
|
||||
<data name="Icon.Check" xml:space="preserve">
|
||||
<value>Check</value>
|
||||
</data>
|
||||
<data name="Icon.ChevronBottom" xml:space="preserve">
|
||||
<value>Chevron Bottom</value>
|
||||
</data>
|
||||
<data name="Icon.ChevronLeft" xml:space="preserve">
|
||||
<value>Chevron Left</value>
|
||||
</data>
|
||||
<data name="Icon.ChevronRight" xml:space="preserve">
|
||||
<value>Chevron Right</value>
|
||||
</data>
|
||||
<data name="Icon.ChevronTop" xml:space="preserve">
|
||||
<value>Chevron Top</value>
|
||||
</data>
|
||||
<data name="Icon.CircleCheck" xml:space="preserve">
|
||||
<value>Circle Check</value>
|
||||
</data>
|
||||
<data name="Icon.CircleX" xml:space="preserve">
|
||||
<value>Circle X</value>
|
||||
</data>
|
||||
<data name="Icon.Clipboard" xml:space="preserve">
|
||||
<value>Clipboard</value>
|
||||
</data>
|
||||
<data name="Icon.Clock" xml:space="preserve">
|
||||
<value>Clock</value>
|
||||
</data>
|
||||
<data name="Icon.CloudDownload" xml:space="preserve">
|
||||
<value>Cloud Download</value>
|
||||
</data>
|
||||
<data name="Icon.CloudUpload" xml:space="preserve">
|
||||
<value>Cloud Upload</value>
|
||||
</data>
|
||||
<data name="Icon.Cloud" xml:space="preserve">
|
||||
<value>Cloud</value>
|
||||
</data>
|
||||
<data name="Icon.Cloudy" xml:space="preserve">
|
||||
<value>Cloudy</value>
|
||||
</data>
|
||||
<data name="Icon.Code" xml:space="preserve">
|
||||
<value>Code</value>
|
||||
</data>
|
||||
<data name="Icon.Cog" xml:space="preserve">
|
||||
<value>Cog</value>
|
||||
</data>
|
||||
<data name="Icon.CollapseDown" xml:space="preserve">
|
||||
<value>Collapse Down</value>
|
||||
</data>
|
||||
<data name="Icon.CollapseLeft" xml:space="preserve">
|
||||
<value>Collapse Left</value>
|
||||
</data>
|
||||
<data name="Icon.CollapseRight" xml:space="preserve">
|
||||
<value>Collapse Right</value>
|
||||
</data>
|
||||
<data name="Icon.CollapseUp" xml:space="preserve">
|
||||
<value>Collapse Up</value>
|
||||
</data>
|
||||
<data name="Icon.Command" xml:space="preserve">
|
||||
<value>Command</value>
|
||||
</data>
|
||||
<data name="Icon.CommentSquare" xml:space="preserve">
|
||||
<value>Comment Square</value>
|
||||
</data>
|
||||
<data name="Icon.Compass" xml:space="preserve">
|
||||
<value>Compass</value>
|
||||
</data>
|
||||
<data name="Icon.Contrast" xml:space="preserve">
|
||||
<value>Contrast</value>
|
||||
</data>
|
||||
<data name="Icon.Copywriting" xml:space="preserve">
|
||||
<value>Copywriting</value>
|
||||
</data>
|
||||
<data name="Icon.CreditCard" xml:space="preserve">
|
||||
<value>Credit Card</value>
|
||||
</data>
|
||||
<data name="Icon.Crop" xml:space="preserve">
|
||||
<value>Crop</value>
|
||||
</data>
|
||||
<data name="Icon.Dashboard" xml:space="preserve">
|
||||
<value>Dashboard</value>
|
||||
</data>
|
||||
<data name="Icon.DataTransferDownload" xml:space="preserve">
|
||||
<value>Data Transfer Download</value>
|
||||
</data>
|
||||
<data name="Icon.DataTransferUpload" xml:space="preserve">
|
||||
<value>Data Transfer Upload</value>
|
||||
</data>
|
||||
<data name="Icon.Delete" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="Icon.Dial" xml:space="preserve">
|
||||
<value>Dial</value>
|
||||
</data>
|
||||
<data name="Icon.Document" xml:space="preserve">
|
||||
<value>Document</value>
|
||||
</data>
|
||||
<data name="Icon.Dollar" xml:space="preserve">
|
||||
<value>Dollar</value>
|
||||
</data>
|
||||
<data name="Icon.DoubleQuoteSansLeft" xml:space="preserve">
|
||||
<value>Double Quote Sans Left</value>
|
||||
</data>
|
||||
<data name="Icon.DoubleQuoteSansRight" xml:space="preserve">
|
||||
<value>Double Quote Sans Right</value>
|
||||
</data>
|
||||
<data name="Icon.DoubleQuoteSerifLeft" xml:space="preserve">
|
||||
<value>Double Quote Serif Left</value>
|
||||
</data>
|
||||
<data name="Icon.DoubleQuoteSerifRight" xml:space="preserve">
|
||||
<value>Double Quote Serif Right</value>
|
||||
</data>
|
||||
<data name="Icon.Droplet" xml:space="preserve">
|
||||
<value>Droplet</value>
|
||||
</data>
|
||||
<data name="Icon.Eject" xml:space="preserve">
|
||||
<value>Eject</value>
|
||||
</data>
|
||||
<data name="Icon.Elevator" xml:space="preserve">
|
||||
<value>Elevator</value>
|
||||
</data>
|
||||
<data name="Icon.Ellipses" xml:space="preserve">
|
||||
<value>Ellipses</value>
|
||||
</data>
|
||||
<data name="Icon.EnvelopeClosed" xml:space="preserve">
|
||||
<value>Envelope Closed</value>
|
||||
</data>
|
||||
<data name="Icon.EnvelopeOpen" xml:space="preserve">
|
||||
<value>Envelope Open</value>
|
||||
</data>
|
||||
<data name="Icon.Euro" xml:space="preserve">
|
||||
<value>Euro</value>
|
||||
</data>
|
||||
<data name="Icon.Excerpt" xml:space="preserve">
|
||||
<value>Excerpt</value>
|
||||
</data>
|
||||
<data name="Icon.ExpandDown" xml:space="preserve">
|
||||
<value>Expand Down</value>
|
||||
</data>
|
||||
<data name="Icon.ExpandLeft" xml:space="preserve">
|
||||
<value>Expand Left</value>
|
||||
</data>
|
||||
<data name="Icon.ExpandRight" xml:space="preserve">
|
||||
<value>Expand Right</value>
|
||||
</data>
|
||||
<data name="Icon.ExpandUp" xml:space="preserve">
|
||||
<value>Expand Up</value>
|
||||
</data>
|
||||
<data name="Icon.ExternalLink" xml:space="preserve">
|
||||
<value>External Link</value>
|
||||
</data>
|
||||
<data name="Icon.Eye" xml:space="preserve">
|
||||
<value>Eye</value>
|
||||
</data>
|
||||
<data name="Icon.Eyedropper" xml:space="preserve">
|
||||
<value>Eyedropper</value>
|
||||
</data>
|
||||
<data name="Icon.File" xml:space="preserve">
|
||||
<value>File</value>
|
||||
</data>
|
||||
<data name="Icon.Fire" xml:space="preserve">
|
||||
<value>Fire</value>
|
||||
</data>
|
||||
<data name="Icon.Flag" xml:space="preserve">
|
||||
<value>Flag</value>
|
||||
</data>
|
||||
<data name="Icon.Flash" xml:space="preserve">
|
||||
<value>Flash</value>
|
||||
</data>
|
||||
<data name="Icon.Folder" xml:space="preserve">
|
||||
<value>Folder</value>
|
||||
</data>
|
||||
<data name="Icon.Fork" xml:space="preserve">
|
||||
<value>Fork</value>
|
||||
</data>
|
||||
<data name="Icon.FullscreenEnter" xml:space="preserve">
|
||||
<value>Fullscreen Enter</value>
|
||||
</data>
|
||||
<data name="Icon.FullscreenExit" xml:space="preserve">
|
||||
<value>Fullscreen Exit</value>
|
||||
</data>
|
||||
<data name="Icon.Globe" xml:space="preserve">
|
||||
<value>Globe</value>
|
||||
</data>
|
||||
<data name="Icon.Graph" xml:space="preserve">
|
||||
<value>Graph</value>
|
||||
</data>
|
||||
<data name="Icon.GridFourUp" xml:space="preserve">
|
||||
<value>Grid Four Up</value>
|
||||
</data>
|
||||
<data name="Icon.GridThreeUp" xml:space="preserve">
|
||||
<value>Grid Three Up</value>
|
||||
</data>
|
||||
<data name="Icon.GridTwoUp" xml:space="preserve">
|
||||
<value>Grid Two Up</value>
|
||||
</data>
|
||||
<data name="Icon.HardDrive" xml:space="preserve">
|
||||
<value>Hard Drive</value>
|
||||
</data>
|
||||
<data name="Icon.Header" xml:space="preserve">
|
||||
<value>Header</value>
|
||||
</data>
|
||||
<data name="Icon.Headphones" xml:space="preserve">
|
||||
<value>Headphones</value>
|
||||
</data>
|
||||
<data name="Icon.Heart" xml:space="preserve">
|
||||
<value>Heart</value>
|
||||
</data>
|
||||
<data name="Icon.Home" xml:space="preserve">
|
||||
<value>Home</value>
|
||||
</data>
|
||||
<data name="Icon.Image" xml:space="preserve">
|
||||
<value>Image</value>
|
||||
</data>
|
||||
<data name="Icon.Inbox" xml:space="preserve">
|
||||
<value>Inbox</value>
|
||||
</data>
|
||||
<data name="Icon.Infinity" xml:space="preserve">
|
||||
<value>Infinity</value>
|
||||
</data>
|
||||
<data name="Icon.Info" xml:space="preserve">
|
||||
<value>Info</value>
|
||||
</data>
|
||||
<data name="Icon.Italic" xml:space="preserve">
|
||||
<value>Italic</value>
|
||||
</data>
|
||||
<data name="Icon.JustifyCenter" xml:space="preserve">
|
||||
<value>Justify Center</value>
|
||||
</data>
|
||||
<data name="Icon.JustifyLeft" xml:space="preserve">
|
||||
<value>Justify Left</value>
|
||||
</data>
|
||||
<data name="Icon.JustifyRight" xml:space="preserve">
|
||||
<value>Justify Right</value>
|
||||
</data>
|
||||
<data name="Icon.Key" xml:space="preserve">
|
||||
<value>Key</value>
|
||||
</data>
|
||||
<data name="Icon.Laptop" xml:space="preserve">
|
||||
<value>Laptop</value>
|
||||
</data>
|
||||
<data name="Icon.Layers" xml:space="preserve">
|
||||
<value>Layers</value>
|
||||
</data>
|
||||
<data name="Icon.Lightbulb" xml:space="preserve">
|
||||
<value>Lightbulb</value>
|
||||
</data>
|
||||
<data name="Icon.LinkBroken" xml:space="preserve">
|
||||
<value>Link Broken</value>
|
||||
</data>
|
||||
<data name="Icon.LinkIntact" xml:space="preserve">
|
||||
<value>Link Intact</value>
|
||||
</data>
|
||||
<data name="Icon.ListRich" xml:space="preserve">
|
||||
<value>List Rich</value>
|
||||
</data>
|
||||
<data name="Icon.List" xml:space="preserve">
|
||||
<value>List</value>
|
||||
</data>
|
||||
<data name="Icon.Location" xml:space="preserve">
|
||||
<value>Location</value>
|
||||
</data>
|
||||
<data name="Icon.LockLocked" xml:space="preserve">
|
||||
<value>Lock Locked</value>
|
||||
</data>
|
||||
<data name="Icon.LockUnlocked" xml:space="preserve">
|
||||
<value>Lock Unlocked</value>
|
||||
</data>
|
||||
<data name="Icon.LoopCircular" xml:space="preserve">
|
||||
<value>Loop Circular</value>
|
||||
</data>
|
||||
<data name="Icon.LoopSquare" xml:space="preserve">
|
||||
<value>Loop Square</value>
|
||||
</data>
|
||||
<data name="Icon.Loop" xml:space="preserve">
|
||||
<value>Loop</value>
|
||||
</data>
|
||||
<data name="Icon.MagnifyingGlass" xml:space="preserve">
|
||||
<value>Magnifying Glass</value>
|
||||
</data>
|
||||
<data name="Icon.MapMarker" xml:space="preserve">
|
||||
<value>Map Marker</value>
|
||||
</data>
|
||||
<data name="Icon.Map" xml:space="preserve">
|
||||
<value>Map</value>
|
||||
</data>
|
||||
<data name="Icon.MediaPause" xml:space="preserve">
|
||||
<value>Media Pause</value>
|
||||
</data>
|
||||
<data name="Icon.MediaPlay" xml:space="preserve">
|
||||
<value>Media Play</value>
|
||||
</data>
|
||||
<data name="Icon.MediaRecord" xml:space="preserve">
|
||||
<value>Media Record</value>
|
||||
</data>
|
||||
<data name="Icon.MediaSkipBackward" xml:space="preserve">
|
||||
<value>Media Skip Backward</value>
|
||||
</data>
|
||||
<data name="Icon.MediaSkipForward" xml:space="preserve">
|
||||
<value>Media Skip Forward</value>
|
||||
</data>
|
||||
<data name="Icon.MediaStepBackward" xml:space="preserve">
|
||||
<value>Media Step Backward</value>
|
||||
</data>
|
||||
<data name="Icon.MediaStepForward" xml:space="preserve">
|
||||
<value>Media Step Forward</value>
|
||||
</data>
|
||||
<data name="Icon.MediaStop" xml:space="preserve">
|
||||
<value>Media Stop</value>
|
||||
</data>
|
||||
<data name="Icon.MedicalCross" xml:space="preserve">
|
||||
<value>Medical Cross</value>
|
||||
</data>
|
||||
<data name="Icon.Menu" xml:space="preserve">
|
||||
<value>Menu</value>
|
||||
</data>
|
||||
<data name="Icon.Microphone" xml:space="preserve">
|
||||
<value>Microphone</value>
|
||||
</data>
|
||||
<data name="Icon.Minus" xml:space="preserve">
|
||||
<value>Minus</value>
|
||||
</data>
|
||||
<data name="Icon.Monitor" xml:space="preserve">
|
||||
<value>Monitor</value>
|
||||
</data>
|
||||
<data name="Icon.Moon" xml:space="preserve">
|
||||
<value>Moon</value>
|
||||
</data>
|
||||
<data name="Icon.Move" xml:space="preserve">
|
||||
<value>Move</value>
|
||||
</data>
|
||||
<data name="Icon.MusicalNote" xml:space="preserve">
|
||||
<value>Musical Note</value>
|
||||
</data>
|
||||
<data name="Icon.Paperclip" xml:space="preserve">
|
||||
<value>Paperclip</value>
|
||||
</data>
|
||||
<data name="Icon.Pencil" xml:space="preserve">
|
||||
<value>Pencil</value>
|
||||
</data>
|
||||
<data name="Icon.People" xml:space="preserve">
|
||||
<value>People</value>
|
||||
</data>
|
||||
<data name="Icon.Person" xml:space="preserve">
|
||||
<value>Person</value>
|
||||
</data>
|
||||
<data name="Icon.Phone" xml:space="preserve">
|
||||
<value>Phone</value>
|
||||
</data>
|
||||
<data name="Icon.PieChart" xml:space="preserve">
|
||||
<value>Pie Chart</value>
|
||||
</data>
|
||||
<data name="Icon.Pin" xml:space="preserve">
|
||||
<value>Pin</value>
|
||||
</data>
|
||||
<data name="Icon.PlayCircle" xml:space="preserve">
|
||||
<value>Play Circle</value>
|
||||
</data>
|
||||
<data name="Icon.Plus" xml:space="preserve">
|
||||
<value>Plus</value>
|
||||
</data>
|
||||
<data name="Icon.PowerStandby" xml:space="preserve">
|
||||
<value>Power Standby</value>
|
||||
</data>
|
||||
<data name="Icon.Print" xml:space="preserve">
|
||||
<value>Print</value>
|
||||
</data>
|
||||
<data name="Icon.Project" xml:space="preserve">
|
||||
<value>Project</value>
|
||||
</data>
|
||||
<data name="Icon.Pulse" xml:space="preserve">
|
||||
<value>Pulse</value>
|
||||
</data>
|
||||
<data name="Icon.PuzzlePiece" xml:space="preserve">
|
||||
<value>Puzzle Piece</value>
|
||||
</data>
|
||||
<data name="Icon.QuestionMark" xml:space="preserve">
|
||||
<value>Question Mark</value>
|
||||
</data>
|
||||
<data name="Icon.Rain" xml:space="preserve">
|
||||
<value>Rain</value>
|
||||
</data>
|
||||
<data name="Icon.Random" xml:space="preserve">
|
||||
<value>Random</value>
|
||||
</data>
|
||||
<data name="Icon.Reload" xml:space="preserve">
|
||||
<value>Reload</value>
|
||||
</data>
|
||||
<data name="Icon.ResizeBoth" xml:space="preserve">
|
||||
<value>Resize Both</value>
|
||||
</data>
|
||||
<data name="Icon.ResizeHeight" xml:space="preserve">
|
||||
<value>Resize Height</value>
|
||||
</data>
|
||||
<data name="Icon.ResizeWidth" xml:space="preserve">
|
||||
<value>Resize Width</value>
|
||||
</data>
|
||||
<data name="Icon.RssAlt" xml:space="preserve">
|
||||
<value>Rss Alt</value>
|
||||
</data>
|
||||
<data name="Icon.Rss" xml:space="preserve">
|
||||
<value>Rss</value>
|
||||
</data>
|
||||
<data name="Icon.Script" xml:space="preserve">
|
||||
<value>Script</value>
|
||||
</data>
|
||||
<data name="Icon.ShareBoxed" xml:space="preserve">
|
||||
<value>Share Boxed</value>
|
||||
</data>
|
||||
<data name="Icon.Share" xml:space="preserve">
|
||||
<value>Share</value>
|
||||
</data>
|
||||
<data name="Icon.Shield" xml:space="preserve">
|
||||
<value>Shield</value>
|
||||
</data>
|
||||
<data name="Icon.Signal" xml:space="preserve">
|
||||
<value>Signal</value>
|
||||
</data>
|
||||
<data name="Icon.Signpost" xml:space="preserve">
|
||||
<value>Signpost</value>
|
||||
</data>
|
||||
<data name="Icon.SortAscending" xml:space="preserve">
|
||||
<value>Sort Ascending</value>
|
||||
</data>
|
||||
<data name="Icon.SortDescending" xml:space="preserve">
|
||||
<value>Sort Descending</value>
|
||||
</data>
|
||||
<data name="Icon.Spreadsheet" xml:space="preserve">
|
||||
<value>Spreadsheet</value>
|
||||
</data>
|
||||
<data name="Icon.Star" xml:space="preserve">
|
||||
<value>Star</value>
|
||||
</data>
|
||||
<data name="Icon.Sun" xml:space="preserve">
|
||||
<value>Sun</value>
|
||||
</data>
|
||||
<data name="Icon.Tablet" xml:space="preserve">
|
||||
<value>Tablet</value>
|
||||
</data>
|
||||
<data name="Icon.Tag" xml:space="preserve">
|
||||
<value>Tag</value>
|
||||
</data>
|
||||
<data name="Icon.Tags" xml:space="preserve">
|
||||
<value>Tags</value>
|
||||
</data>
|
||||
<data name="Icon.Target" xml:space="preserve">
|
||||
<value>Target</value>
|
||||
</data>
|
||||
<data name="Icon.Task" xml:space="preserve">
|
||||
<value>Task</value>
|
||||
</data>
|
||||
<data name="Icon.Terminal" xml:space="preserve">
|
||||
<value>Terminal</value>
|
||||
</data>
|
||||
<data name="Icon.Text" xml:space="preserve">
|
||||
<value>Text</value>
|
||||
</data>
|
||||
<data name="Icon.ThumbDown" xml:space="preserve">
|
||||
<value>Thumb Down</value>
|
||||
</data>
|
||||
<data name="Icon.ThumbUp" xml:space="preserve">
|
||||
<value>Thumb Up</value>
|
||||
</data>
|
||||
<data name="Icon.Timer" xml:space="preserve">
|
||||
<value>Timer</value>
|
||||
</data>
|
||||
<data name="Icon.Transfer" xml:space="preserve">
|
||||
<value>Transfer</value>
|
||||
</data>
|
||||
<data name="Icon.Trash" xml:space="preserve">
|
||||
<value>Trash</value>
|
||||
</data>
|
||||
<data name="Icon.Underline" xml:space="preserve">
|
||||
<value>Underline</value>
|
||||
</data>
|
||||
<data name="Icon.VerticalAlignBottom" xml:space="preserve">
|
||||
<value>Vertical Align Bottom</value>
|
||||
</data>
|
||||
<data name="Icon.VerticalAlignCenter" xml:space="preserve">
|
||||
<value>Vertical Align Center</value>
|
||||
</data>
|
||||
<data name="Icon.VerticalAlignTop" xml:space="preserve">
|
||||
<value>Vertical Align Top</value>
|
||||
</data>
|
||||
<data name="Icon.Video" xml:space="preserve">
|
||||
<value>Video</value>
|
||||
</data>
|
||||
<data name="Icon.VolumeHigh" xml:space="preserve">
|
||||
<value>Volume High</value>
|
||||
</data>
|
||||
<data name="Icon.VolumeLow" xml:space="preserve">
|
||||
<value>Volume Low</value>
|
||||
</data>
|
||||
<data name="Icon.VolumeOff" xml:space="preserve">
|
||||
<value>Volume Off</value>
|
||||
</data>
|
||||
<data name="Icon.Warning" xml:space="preserve">
|
||||
<value>Warning</value>
|
||||
</data>
|
||||
<data name="Icon.Wifi" xml:space="preserve">
|
||||
<value>Wifi</value>
|
||||
</data>
|
||||
<data name="Icon.Wrench" xml:space="preserve">
|
||||
<value>Wrench</value>
|
||||
</data>
|
||||
<data name="Icon.X" xml:space="preserve">
|
||||
<value>X</value>
|
||||
</data>
|
||||
<data name="Icon.Yen" xml:space="preserve">
|
||||
<value>Yen</value>
|
||||
</data>
|
||||
<data name="Icon.ZoomIn" xml:space="preserve">
|
||||
<value>Zoom In</value>
|
||||
</data>
|
||||
<data name="Icon.ZoomOut" xml:space="preserve">
|
||||
<value>Zoom Out</value>
|
||||
</data>
|
||||
</root>
|
@ -124,7 +124,7 @@
|
||||
<value>Database:</value>
|
||||
</data>
|
||||
<data name="ApplicationAdmin" xml:space="preserve">
|
||||
<value>Application Administrator</value>
|
||||
<value>Application Administration</value>
|
||||
</data>
|
||||
<data name="InstallNow" xml:space="preserve">
|
||||
<value>Install Now</value>
|
||||
@ -180,4 +180,7 @@
|
||||
<data name="EnterConnectionString" xml:space="preserve">
|
||||
<value>Enter Connection String</value>
|
||||
</data>
|
||||
<data name="Template" xml:space="preserve">
|
||||
<value>Select a site template</value>
|
||||
</data>
|
||||
</root>
|
@ -162,4 +162,7 @@
|
||||
<data name="Name.Text" xml:space="preserve">
|
||||
<value>Name:</value>
|
||||
</data>
|
||||
<data name="DownloadFiles.Heading" xml:space="preserve">
|
||||
<value>Download Files</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -150,4 +150,7 @@
|
||||
<data name="Description.Text" xml:space="preserve">
|
||||
<value>Description:</value>
|
||||
</data>
|
||||
<data name="File Management" xml:space="preserve">
|
||||
<value>File Management</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -178,9 +178,21 @@
|
||||
<value>Capacity:</value>
|
||||
</data>
|
||||
<data name="ImageSizes.HelpText" xml:space="preserve">
|
||||
<value>Enter a list of image sizes which can be generated dynamically from uploaded images (ie. 200x200,x200,200x)</value>
|
||||
<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>
|
||||
</data>
|
||||
<data name="ImageSizes.Text" xml:space="preserve">
|
||||
<value>Image Sizes:</value>
|
||||
</data>
|
||||
<data name="FolderManagement.Title" xml:space="preserve">
|
||||
<value>Folder Management!</value>
|
||||
</data>
|
||||
<data name="Private" xml:space="preserve">
|
||||
<value>Private</value>
|
||||
</data>
|
||||
<data name="Public" xml:space="preserve">
|
||||
<value>Public</value>
|
||||
</data>
|
||||
<data name="Folder Management" xml:space="preserve">
|
||||
<value>Folder Management</value>
|
||||
</data>
|
||||
</root>
|
@ -195,4 +195,7 @@
|
||||
<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">
|
||||
<value>Refresh</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -136,7 +136,7 @@
|
||||
<value>The function that was performed</value>
|
||||
</data>
|
||||
<data name="Category.HelpText" xml:space="preserve">
|
||||
<value>The categories that were affected</value>
|
||||
<value>The fully qualified type type that was affected</value>
|
||||
</data>
|
||||
<data name="Page.HelpText" xml:space="preserve">
|
||||
<value>The page that was affected</value>
|
||||
@ -178,7 +178,7 @@
|
||||
<value>Function: </value>
|
||||
</data>
|
||||
<data name="Category.Text" xml:space="preserve">
|
||||
<value>Category: </value>
|
||||
<value>Type Name: </value>
|
||||
</data>
|
||||
<data name="Page.Text" xml:space="preserve">
|
||||
<value>Page: </value>
|
||||
|
@ -124,7 +124,7 @@
|
||||
<value>Error Loading Packages</value>
|
||||
</data>
|
||||
<data name="Success.Module.Download" xml:space="preserve">
|
||||
<value>Module Package Saved Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||
<value>Module Package Downloaded Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||
</data>
|
||||
<data name="Error.Module.Download" xml:space="preserve">
|
||||
<value>Error Downloading Module</value>
|
||||
@ -136,9 +136,12 @@
|
||||
<value>No Modules Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||
</data>
|
||||
<data name="Download.Heading" xml:space="preserve">
|
||||
<value>Download</value>
|
||||
<value>Marketplace</value>
|
||||
</data>
|
||||
<data name="Upload.Heading" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
<data name="Product" xml:space="preserve">
|
||||
<value>Product</value>
|
||||
</data>
|
||||
</root>
|
@ -132,6 +132,9 @@
|
||||
<data name="Message.Require.ValidName" xml:space="preserve">
|
||||
<value>You Must Provide A Valid Owner Name And Module Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template</value>
|
||||
</data>
|
||||
<data name="Message.Require.ValidDescription" xml:space="preserve">
|
||||
<value>You Must Provide A Valid Description (ie. No Punctuation)</value>
|
||||
</data>
|
||||
<data name="OwnerName.HelpText" xml:space="preserve">
|
||||
<value>Enter the name of the organization who is developing this module. It should not contain spaces or punctuation.</value>
|
||||
</data>
|
||||
|
@ -196,7 +196,7 @@
|
||||
<value>Information</value>
|
||||
</data>
|
||||
<data name="PackageName.HelpText" xml:space="preserve">
|
||||
<value>The unique name of the package from which this module was installed</value>
|
||||
<value>The unique name of the package from which this module was installed. This value must be specified within the module's IModule interface specification.</value>
|
||||
</data>
|
||||
<data name="PackageName.Text" xml:space="preserve">
|
||||
<value>Package Name:</value>
|
||||
@ -219,4 +219,25 @@
|
||||
<data name="Message.DuplicateName" xml:space="preserve">
|
||||
<value>A Module With The Name Specified Already Exists</value>
|
||||
</data>
|
||||
<data name="IsEnabled.HelpText" xml:space="preserve">
|
||||
<value>Is module enabled for this site?</value>
|
||||
</data>
|
||||
<data name="IsEnabled.Text" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
<data name="View License" xml:space="preserve">
|
||||
<value>View License</value>
|
||||
</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>
|
@ -144,8 +144,11 @@
|
||||
<data name="DeleteModule.Header" xml:space="preserve">
|
||||
<value>Delete Module</value>
|
||||
</data>
|
||||
<data name="DeleteModule.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="InUse" xml:space="preserve">
|
||||
<value>In Use</value>
|
||||
<value>In Use?</value>
|
||||
</data>
|
||||
<data name="EditModule.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
@ -153,4 +156,7 @@
|
||||
<data name="Modules" xml:space="preserve">
|
||||
<value>Modules</value>
|
||||
</data>
|
||||
<data name="Enabled" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -132,4 +132,7 @@
|
||||
<data name="Success.Content.Export" xml:space="preserve">
|
||||
<value>Content Exported Successfully</value>
|
||||
</data>
|
||||
<data name="Export Content" xml:space="preserve">
|
||||
<value>Export Content</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -138,4 +138,7 @@
|
||||
<data name="Message.Required.ImportContent" xml:space="preserve">
|
||||
<value>You Must Enter Some Content To Import</value>
|
||||
</data>
|
||||
<data name="Import Content" xml:space="preserve">
|
||||
<value>Import Content</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -150,4 +150,19 @@
|
||||
<data name="Error.Module.Load" xml:space="preserve">
|
||||
<value>A Problem Was Encountered Loading Module {0}. The Module Is Either Invalid Or Does Not Exist.</value>
|
||||
</data>
|
||||
<data name="Module.HelpText" xml:space="preserve">
|
||||
<value>The name of the module</value>
|
||||
</data>
|
||||
<data name="Module.Text" xml:space="preserve">
|
||||
<value>Module:</value>
|
||||
</data>
|
||||
<data name="Module Settings" xml:space="preserve">
|
||||
<value>Module Settings</value>
|
||||
</data>
|
||||
<data name="Pane.HelpText" xml:space="preserve">
|
||||
<value>The pane where the module will be displayed</value>
|
||||
</data>
|
||||
<data name="Pane.Text" xml:space="preserve">
|
||||
<value>Pane:</value>
|
||||
</data>
|
||||
</root>
|
@ -150,8 +150,8 @@
|
||||
<data name="Container.Select" xml:space="preserve">
|
||||
<value>Select Container</value>
|
||||
</data>
|
||||
<data name="Error.Page.Initialize" xml:space="preserve">
|
||||
<value>Error Initializing Page</value>
|
||||
<data name="Error.Page.Load" xml:space="preserve">
|
||||
<value>Error Loading Page</value>
|
||||
</data>
|
||||
<data name="Error.ChildPage.Load" xml:space="preserve">
|
||||
<value>Error Loading Child Pages For Parent</value>
|
||||
@ -228,13 +228,31 @@
|
||||
<data name="Appearance.Name" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
</data>
|
||||
<data name="Meta.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter meta tags (in exactly the form you want them to be included in the page output).</value>
|
||||
<data name="HeadContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page head (ie. meta, link, or script tags)</value>
|
||||
</data>
|
||||
<data name="Meta.Text" xml:space="preserve">
|
||||
<value>Meta:</value>
|
||||
<data name="HeadContent.Text" xml:space="preserve">
|
||||
<value>Head Content:</value>
|
||||
</data>
|
||||
<data name="Message.Page.Reserved" xml:space="preserve">
|
||||
<value>The page name {0} is reserved. Please enter a different name for your page.</value>
|
||||
</data>
|
||||
<data name="BodyContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page body (ie. script tags)</value>
|
||||
</data>
|
||||
<data name="BodyContent.Text" xml:space="preserve">
|
||||
<value>Body Content:</value>
|
||||
</data>
|
||||
<data name="PageContent.Heading" xml:space="preserve">
|
||||
<value>Page Content</value>
|
||||
</data>
|
||||
<data name="ThemeChanged.Message" xml:space="preserve">
|
||||
<value>Please Note That Overriding The Default Site Theme With An Unrelated Page Theme May Result In Compatibility Issues For Your Site</value>
|
||||
</data>
|
||||
<data name="Permissions.Heading" xml:space="preserve">
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
<data name="Theme.Heading" xml:space="preserve">
|
||||
<value>Theme Settings</value>
|
||||
</data>
|
||||
</root>
|
@ -264,13 +264,25 @@
|
||||
<data name="Clickable.Text" xml:space="preserve">
|
||||
<value>Clickable?</value>
|
||||
</data>
|
||||
<data name="Meta.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter meta tags (in exactly the form you want them to be included in the page output).</value>
|
||||
<data name="HeadContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page head (ie. meta, link, or script tags)</value>
|
||||
</data>
|
||||
<data name="Meta.Text" xml:space="preserve">
|
||||
<value>Meta:</value>
|
||||
<data name="HeadContent.Text" xml:space="preserve">
|
||||
<value>Head Content:</value>
|
||||
</data>
|
||||
<data name="Message.Page.Reserved" xml:space="preserve">
|
||||
<value>The page name {0} is reserved. Please enter a different name for your page.</value>
|
||||
</data>
|
||||
<data name="BodyContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page body (ie. script tags)</value>
|
||||
</data>
|
||||
<data name="BodyContent.Text" xml:space="preserve">
|
||||
<value>Body Content:</value>
|
||||
</data>
|
||||
<data name="PageContent.Heading" xml:space="preserve">
|
||||
<value>Page Content</value>
|
||||
</data>
|
||||
<data name="ThemeChanged.Message" xml:space="preserve">
|
||||
<value>Please Note That Overriding The Default Site Theme With An Unrelated Page Theme May Result In Compatibility Issues For Your Site</value>
|
||||
</data>
|
||||
</root>
|
@ -183,4 +183,10 @@
|
||||
<data name="Private.Text" xml:space="preserve">
|
||||
<value>Private? </value>
|
||||
</data>
|
||||
<data name="Validation.HelpText" xml:space="preserve">
|
||||
<value>Optionally provide a regular expression (RegExp) for validating the value entered</value>
|
||||
</data>
|
||||
<data name="Validation.Text" xml:space="preserve">
|
||||
<value>Validation:</value>
|
||||
</data>
|
||||
</root>
|
@ -138,4 +138,13 @@
|
||||
<data name="EditProfile.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="Category" xml:space="preserve">
|
||||
<value>Category</value>
|
||||
</data>
|
||||
<data name="Order" xml:space="preserve">
|
||||
<value>Order</value>
|
||||
</data>
|
||||
<data name="Title" xml:space="preserve">
|
||||
<value>Title</value>
|
||||
</data>
|
||||
</root>
|
@ -120,9 +120,15 @@
|
||||
<data name="DeleteModule.Header" xml:space="preserve">
|
||||
<value>Delete Module</value>
|
||||
</data>
|
||||
<data name="DeleteModule.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="DeletePage.Header" xml:space="preserve">
|
||||
<value>Delete Page</value>
|
||||
</data>
|
||||
<data name="DeletePage.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="NoPage.Deleted" xml:space="preserve">
|
||||
<value>No Deleted Pages</value>
|
||||
</data>
|
||||
|
@ -136,7 +136,7 @@
|
||||
<value>User Account Created. Please Check Your Email For Verification Instructions.</value>
|
||||
</data>
|
||||
<data name="Error.User.AddInfo" xml:space="preserve">
|
||||
<value>Error Adding User. Please Ensure Password Meets Complexity Requirements And Username Is Not Already In Use.</value>
|
||||
<value>Error Adding User. Please Ensure Password Meets Complexity Requirements And Username And Email Is Not Already In Use.</value>
|
||||
</data>
|
||||
<data name="Message.Password.NoMatch" xml:space="preserve">
|
||||
<value>Passwords Entered Do Not Match</value>
|
||||
@ -177,19 +177,4 @@
|
||||
<data name="Username.Text" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
</data>
|
||||
<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>
|
||||
</data>
|
||||
<data name="Password.DigitRequirement" xml:space="preserve">
|
||||
<value>At Least One Digit</value>
|
||||
</data>
|
||||
<data name="Password.LowercaseRequirement" xml:space="preserve">
|
||||
<value>At Least One Lowercase Letter</value>
|
||||
</data>
|
||||
<data name="Password.PunctuationRequirement" xml:space="preserve">
|
||||
<value>At Least One Punctuation Mark</value>
|
||||
</data>
|
||||
<data name="Password.UppercaseRequirement" xml:space="preserve">
|
||||
<value>At Least One Uppercase Letter</value>
|
||||
</data>
|
||||
</root>
|
@ -166,7 +166,7 @@
|
||||
<value>The name of the database used for the site</value>
|
||||
</data>
|
||||
<data name="Aliases.HelpText" xml:space="preserve">
|
||||
<value>The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder).</value>
|
||||
<value>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).</value>
|
||||
</data>
|
||||
<data name="IsDeleted.HelpText" xml:space="preserve">
|
||||
<value>Is this site deleted?</value>
|
||||
@ -175,7 +175,7 @@
|
||||
<value>Specify a logo for the site</value>
|
||||
</data>
|
||||
<data name="FavoriteIcon.HelpText" xml:space="preserve">
|
||||
<value>Specify a Favicon</value>
|
||||
<value>Specify a Favicon. The format for the image must be 16×16, 32×32, 48×48, or 64×64 pixels in size, and 8-bit, 24-bit, or 32-bit in color depth. The format of the image must be ICO, PNG, or GIF.</value>
|
||||
</data>
|
||||
<data name="DefaultTheme.HelpText" xml:space="preserve">
|
||||
<value>Select the sites default theme</value>
|
||||
@ -217,7 +217,7 @@
|
||||
<value>Database: </value>
|
||||
</data>
|
||||
<data name="Aliases.Text" xml:space="preserve">
|
||||
<value>Aliases: </value>
|
||||
<value>Urls:</value>
|
||||
</data>
|
||||
<data name="IsDeleted.Text" xml:space="preserve">
|
||||
<value>Deleted? </value>
|
||||
@ -312,6 +312,9 @@
|
||||
<data name="Database.HelpText" xml:space="preserve">
|
||||
<value>The type of database</value>
|
||||
</data>
|
||||
<data name="DeleteSite.Header" xml:space="preserve">
|
||||
<value>Delete Site</value>
|
||||
</data>
|
||||
<data name="DeleteSite.Text" xml:space="preserve">
|
||||
<value>Delete Site</value>
|
||||
</data>
|
||||
@ -322,10 +325,10 @@
|
||||
<value>Default Alias: </value>
|
||||
</data>
|
||||
<data name="Aliases.Heading" xml:space="preserve">
|
||||
<value>Aliases</value>
|
||||
<value>Urls</value>
|
||||
</data>
|
||||
<data name="AliasName" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
<value>Url</value>
|
||||
</data>
|
||||
<data name="AliasDefault" xml:space="preserve">
|
||||
<value>Default?</value>
|
||||
@ -351,4 +354,52 @@
|
||||
<data name="SiteMap.Text" xml:space="preserve">
|
||||
<value>Site Map:</value>
|
||||
</data>
|
||||
<data name="Appearance.Heading" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
</data>
|
||||
<data name="HeadContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page head (ie. meta, link, or script tags)</value>
|
||||
</data>
|
||||
<data name="HeadContent.Text" xml:space="preserve">
|
||||
<value>Head Content:</value>
|
||||
</data>
|
||||
<data name="BodyContent.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter content to be included in the page body (ie. script tags)</value>
|
||||
</data>
|
||||
<data name="BodyContent.Text" xml:space="preserve">
|
||||
<value>Body Content:</value>
|
||||
</data>
|
||||
<data name="PageContent.Heading" xml:space="preserve">
|
||||
<value>Page Content</value>
|
||||
</data>
|
||||
<data name="SMTPEnabled.HelpText" xml:space="preserve">
|
||||
<value>Specify if SMTP is enabled for this site</value>
|
||||
</data>
|
||||
<data name="SMTPEnabled.Text" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
<data name="Version.HelpText" xml:space="preserve">
|
||||
<value>The site version (for site content migrations)</value>
|
||||
</data>
|
||||
<data name="Version.Text" xml:space="preserve">
|
||||
<value>Version:</value>
|
||||
</data>
|
||||
<data name="DeleteAlias.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="DeleteAlias.Header" xml:space="preserve">
|
||||
<value>Delete Alias</value>
|
||||
</data>
|
||||
<data name="SiteGuid.HelpText" xml:space="preserve">
|
||||
<value>The Unique Identifier For The Site</value>
|
||||
</data>
|
||||
<data name="SiteGuid.Text" xml:space="preserve">
|
||||
<value>ID:</value>
|
||||
</data>
|
||||
<data name="Retention.HelpText" xml:space="preserve">
|
||||
<value>Number of days of notifications to retain</value>
|
||||
</data>
|
||||
<data name="Retention.Text" xml:space="preserve">
|
||||
<value>Retention (Days):</value>
|
||||
</data>
|
||||
</root>
|
@ -136,7 +136,7 @@
|
||||
<value>Default Admin Container</value>
|
||||
</data>
|
||||
<data name="Aliases.HelpText" xml:space="preserve">
|
||||
<value>Enter the alias for the server</value>
|
||||
<value>The urls for the site (comman delimited). This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or a virtual folder (ie. domain.com/folder).</value>
|
||||
</data>
|
||||
<data name="DefaultContainer.HelpText" xml:space="preserve">
|
||||
<value>Select the default container for the site</value>
|
||||
@ -145,7 +145,7 @@
|
||||
<value>Database: </value>
|
||||
</data>
|
||||
<data name="Aliases.Text" xml:space="preserve">
|
||||
<value>Aliases: </value>
|
||||
<value>Urls: </value>
|
||||
</data>
|
||||
<data name="DefaultTheme.Text" xml:space="preserve">
|
||||
<value>Default Theme: </value>
|
||||
|
@ -135,4 +135,7 @@
|
||||
<data name="Browse" xml:space="preserve">
|
||||
<value>Browse</value>
|
||||
</data>
|
||||
<data name="AliasName" xml:space="preserve">
|
||||
<value>Url</value>
|
||||
</data>
|
||||
</root>
|
@ -213,17 +213,17 @@
|
||||
<data name="Log.Heading" xml:space="preserve">
|
||||
<value>Log</value>
|
||||
</data>
|
||||
<data name="Register" xml:space="preserve">
|
||||
<data name="Register" xml:space="preserve">
|
||||
<value>Please Register Me For Major Product Updates And Security Bulletins</value>
|
||||
</data>
|
||||
<data name="Success.Register" xml:space="preserve">
|
||||
<value>You Have Been Successfully Registered For Updates</value>
|
||||
</data>
|
||||
<data name="PackageService.HelpText" xml:space="preserve">
|
||||
<value>Specify If The Package Service Is Enabled For Installing Modules, Themes, And Translations</value>
|
||||
<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>
|
||||
</data>
|
||||
<data name="PackageService.Text" xml:space="preserve">
|
||||
<value>Package Service Enabled?</value>
|
||||
<data name="PackageManager.Text" xml:space="preserve">
|
||||
<value>Package Manager:</value>
|
||||
</data>
|
||||
<data name="Swagger.HelpText" xml:space="preserve">
|
||||
<value>Specify If Swagger Is Enabled For Your Server API</value>
|
||||
|
@ -124,7 +124,7 @@
|
||||
<value>Theme: </value>
|
||||
</data>
|
||||
<data name="Success.Theme.Download" xml:space="preserve">
|
||||
<value>Theme Package Saved Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||
<value>Theme Package Downloaded Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||
</data>
|
||||
<data name="Error.Theme.Download" xml:space="preserve">
|
||||
<value>Error Downloading Theme</value>
|
||||
@ -135,4 +135,13 @@
|
||||
<data name="Search.NoResults" xml:space="preserve">
|
||||
<value>No Themes Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||
</data>
|
||||
<data name="Download.Heading" xml:space="preserve">
|
||||
<value>Marketplace</value>
|
||||
</data>
|
||||
<data name="Upload.Heading" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
<data name="Product" xml:space="preserve">
|
||||
<value>Product</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -163,9 +163,33 @@
|
||||
<value>The license of the theme</value>
|
||||
</data>
|
||||
<data name="PackageName.HelpText" xml:space="preserve">
|
||||
<value>The unique name of the package from which this module was installed</value>
|
||||
<value>The unique name of the package from which this theme was installed. This value must be specified within the themee's ITheme interface specification.</value>
|
||||
</data>
|
||||
<data name="PackageName.Text" xml:space="preserve">
|
||||
<value>Package Name:</value>
|
||||
</data>
|
||||
<data name="Information.Heading" xml:space="preserve">
|
||||
<value>Information</value>
|
||||
</data>
|
||||
<data name="IsEnabled.HelpText" xml:space="preserve">
|
||||
<value>Is theme enabled for this site?</value>
|
||||
</data>
|
||||
<data name="IsEnabled.Text" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
<data name="View License" xml:space="preserve">
|
||||
<value>View License</value>
|
||||
</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>
|
@ -138,10 +138,22 @@
|
||||
<data name="DeleteTheme.Header" xml:space="preserve">
|
||||
<value>Delete Theme</value>
|
||||
</data>
|
||||
<data name="DeleteTheme.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="CreateTheme.Text" xml:space="preserve">
|
||||
<value>Create Theme</value>
|
||||
</data>
|
||||
<data name="InstallTheme.Text" xml:space="preserve">
|
||||
<value>Install Theme</value>
|
||||
</data>
|
||||
<data name="ViewTheme.Text" xml:space="preserve">
|
||||
<value>View</value>
|
||||
</data>
|
||||
<data name="EditTheme.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="Enabled" xml:space="preserve">
|
||||
<value>Enabled?</value>
|
||||
</data>
|
||||
</root>
|
@ -141,4 +141,13 @@
|
||||
<data name="Upload.Heading" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
<data name="Message.Text" xml:space="preserve">
|
||||
<value>Framework Is Already Up To Date</value>
|
||||
</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">
|
||||
<value>You Cannot Perform A System Update In A Development Environment</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -141,4 +141,7 @@
|
||||
<data name="Subject.Text" xml:space="preserve">
|
||||
<value>Subject: </value>
|
||||
</data>
|
||||
<data name="Send Notification" xml:space="preserve">
|
||||
<value>Send Notification</value>
|
||||
</data>
|
||||
</root>
|
@ -228,4 +228,10 @@
|
||||
<data name="Profile.Heading" xml:space="preserve">
|
||||
<value>Profile</value>
|
||||
</data>
|
||||
<data name="ViewNotification.Text" xml:space="preserve">
|
||||
<value>View</value>
|
||||
</data>
|
||||
<data name="DeleteNotification.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -144,4 +144,7 @@
|
||||
<data name="OriginalMessage" xml:space="preserve">
|
||||
<value>Original Message</value>
|
||||
</data>
|
||||
<data name="View Notification" xml:space="preserve">
|
||||
<value>View Notification</value>
|
||||
</data>
|
||||
</root>
|
@ -118,7 +118,7 @@
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Error.User.AddCheckPass" xml:space="preserve">
|
||||
<value>Error Adding User. Please Ensure Password Meets Complexity Requirements And Username Is Not Already In Use.</value>
|
||||
<value>Error Adding User. Please Ensure Password Meets Complexity Requirements And Username And Email Is Not Already In Use.</value>
|
||||
</data>
|
||||
<data name="Message.Password.NoMatch" xml:space="preserve">
|
||||
<value>Passwords Entered Do Not Match</value>
|
||||
@ -171,4 +171,10 @@
|
||||
<data name="Password.Placeholder" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
<data name="Notify.HelpText" xml:space="preserve">
|
||||
<value>Indicate if new users should receive an email notification</value>
|
||||
</data>
|
||||
<data name="Notify.Text" xml:space="preserve">
|
||||
<value>Notify?</value>
|
||||
</data>
|
||||
</root>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user