Compare commits
674 Commits
6131948f2a
...
feat/two-f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3688373481 | ||
|
|
b8fbeee322 | ||
|
|
57e4dfb3fb | ||
|
|
afc8d3baf0 | ||
|
|
51d77367ca | ||
|
|
614f3768d9 | ||
|
|
5f780f8d1e | ||
|
|
20825aa3ea | ||
|
|
c5b508d274 | ||
|
|
4eec4451b2 | ||
|
|
ca4718e159 | ||
|
|
33fcb5b70e | ||
|
|
82d8521a25 | ||
|
|
2f9d07312b | ||
|
|
fa36593b26 | ||
|
|
9cdb1409c0 | ||
|
|
95785e8c8b | ||
|
|
6d6e62c8d0 | ||
|
|
1720e137f9 | ||
|
|
3e6e2078bb | ||
|
|
6b0ec9386c | ||
|
|
ee49538f1e | ||
|
|
311009bc97 | ||
|
|
f5028a82fa | ||
|
|
07d70dbd22 | ||
|
|
152050ebf4 | ||
|
|
e27daa4b90 | ||
|
|
808a02968b | ||
|
|
bbd03615e1 | ||
|
|
772d510705 | ||
|
|
aa918d875d | ||
|
|
28fdf0a115 | ||
|
|
120c8623dd | ||
|
|
363329ca18 | ||
|
|
eb0c6dabf4 | ||
|
|
cd88af6807 | ||
|
|
1941de1928 | ||
|
|
22347a0202 | ||
|
|
e54d9d2da8 | ||
|
|
06b1aa9560 | ||
|
|
4f35fe54be | ||
|
|
84e3e4e18d | ||
|
|
7f26bb4766 | ||
|
|
f674be5200 | ||
|
|
0718f24339 | ||
|
|
6abc17c3bf | ||
|
|
cf300d3ade | ||
|
|
be44f9f436 | ||
|
|
80f9107e4e | ||
|
|
c6e9ecfbca | ||
|
|
af5d7c289d | ||
|
|
3267acbeb3 | ||
|
|
95efe58e1b | ||
|
|
867756242e | ||
|
|
713c2f3ed2 | ||
|
|
5a0e258b35 | ||
|
|
651095976a | ||
|
|
fcbee75b9b | ||
|
|
dcb25ffc4c | ||
|
|
618e295634 | ||
|
|
8a2fa2035a | ||
|
|
60109e4deb | ||
|
|
ed6a00dfdf | ||
|
|
c693495928 | ||
|
|
241991721d | ||
|
|
c41d5c4a76 | ||
|
|
27db664b4d | ||
|
|
ba2518cdd2 | ||
|
|
72a0cb78c7 | ||
|
|
e82d7552c2 | ||
|
|
4b50b6c35d | ||
|
|
103d8da6b2 | ||
|
|
15f3bd1bbd | ||
|
|
10a5adeeee | ||
|
|
3b5c6086a9 | ||
|
|
abda0d14e8 | ||
|
|
569ebc87cc | ||
|
|
6b6c8e407c | ||
|
|
556d02870e | ||
|
|
c6fc665002 | ||
|
|
030fd0e45b | ||
|
|
31e647d3e5 | ||
|
|
6dfdd48ec0 | ||
|
|
85cacc822d | ||
|
|
535ca23c86 | ||
|
|
7f1009e402 | ||
|
|
ea4b35f4b4 | ||
|
|
8e1b4e0832 | ||
|
|
4f5b8f9d76 | ||
|
|
f06b41492e | ||
|
|
f0f1275e75 | ||
|
|
085f37de16 | ||
|
|
1657a99aa6 | ||
|
|
ff6d27df8e | ||
|
|
76bd1a102f | ||
|
|
6a6da39bc4 | ||
|
|
137d8e09d4 | ||
|
|
bed51992d2 | ||
|
|
a371abaabe | ||
|
|
90c6e87224 | ||
|
|
4af1534194 | ||
|
|
f39ac57009 | ||
|
|
88d01e4ac7 | ||
|
|
85c33eb0f8 | ||
|
|
1bc31fe0ee | ||
|
|
2e790b4e4c | ||
|
|
19485860a5 | ||
|
|
e33d859603 | ||
|
|
46b8bde162 | ||
|
|
a6468c2ff1 | ||
|
|
40a21a0b89 | ||
|
|
fa44b82493 | ||
|
|
cdec5485c6 | ||
|
|
2a963a1861 | ||
|
|
9d1a2e7254 | ||
|
|
b779ef6f0b | ||
|
|
0c81a86610 | ||
|
|
b11f32bd3c | ||
|
|
b8d9963fac | ||
|
|
e77532ebfd | ||
|
|
ec37518245 | ||
|
|
a1618fc8d0 | ||
|
|
6b65fc28fd | ||
|
|
a763fd6a24 | ||
|
|
28a8e20b63 | ||
|
|
155f80e8b3 | ||
|
|
d8f74971f3 | ||
|
|
44dc7185c6 | ||
|
|
551ba595b6 | ||
|
|
4b77713df4 | ||
|
|
f1ca1e9067 | ||
|
|
0469f057c9 | ||
|
|
b4a97abe6b | ||
|
|
423b293197 | ||
|
|
27618a343e | ||
|
|
fe106c5a8c | ||
|
|
941b98b1a4 | ||
|
|
168c33bfea | ||
|
|
40c25ee111 | ||
|
|
608d79d35b | ||
|
|
62d396932d | ||
|
|
62dcb41526 | ||
|
|
360bb9b3d8 | ||
|
|
1f57914f9e | ||
|
|
9c431ddf56 | ||
|
|
61ff2f8cde | ||
|
|
f2ee509727 | ||
|
|
da06daf776 | ||
|
|
d3104500d4 | ||
|
|
d23b8b9187 | ||
|
|
ec206ab33a | ||
|
|
de6d4b9dd8 | ||
|
|
2943fe0e2d | ||
|
|
33e99f584a | ||
|
|
4a62ab0c56 | ||
|
|
132acd35cc | ||
|
|
ed80839777 | ||
|
|
2114615584 | ||
|
|
6e6f3fd2ed | ||
|
|
5da306acd3 | ||
|
|
18ef1d19b5 | ||
|
|
b76ebd2abc | ||
|
|
d55233061d | ||
|
|
949001791c | ||
|
|
30f93f2439 | ||
|
|
36ffb9511c | ||
|
|
bf84d5c63a | ||
|
|
57f8d0e398 | ||
|
|
bb8bd8ed40 | ||
|
|
ba832acad3 | ||
|
|
6490a3cb82 | ||
|
|
4c077c90db | ||
|
|
9bd5e63128 | ||
|
|
15ce7c9384 | ||
|
|
8707a5cdb5 | ||
|
|
47c7070700 | ||
|
|
fcc3223eb1 | ||
|
|
c4114a3800 | ||
|
|
977486bb7d | ||
|
|
6ccc0d2e0a | ||
|
|
084a9b7db4 | ||
|
|
826844cf46 | ||
|
|
39cff26f2d | ||
|
|
1619801526 | ||
|
|
5a1263ee3a | ||
|
|
bc91baa4fa | ||
|
|
a4882a7bfa | ||
|
|
c254b5b8df | ||
|
|
66718a3fd8 | ||
|
|
99fc2aecd9 | ||
|
|
a41d03aed5 | ||
|
|
6d14b79c43 | ||
|
|
faeac8f290 | ||
|
|
d172faacf3 | ||
|
|
35d6beb3cb | ||
|
|
7ff787ec28 | ||
|
|
f6fc850a20 | ||
|
|
04b8d0ef5d | ||
|
|
891f6368f1 | ||
|
|
e6011b6201 | ||
|
|
8b86114998 | ||
|
|
c20b115faf | ||
|
|
2c8ccd3e7c | ||
|
|
b1f771c320 | ||
|
|
425645a610 | ||
|
|
24e6ffc5ef | ||
|
|
1dd9ce6bbc | ||
|
|
e528fa6409 | ||
|
|
6440dd09d1 | ||
|
|
869493bd97 | ||
|
|
1cb9042736 | ||
|
|
c9410a1e2e | ||
|
|
683ff03a0f | ||
|
|
c9ba7eeaf9 | ||
|
|
c4f0ce7d4b | ||
|
|
dc83486032 | ||
|
|
2a64091c87 | ||
|
|
f65f749208 | ||
|
|
0b6ed00062 | ||
|
|
e87c976e19 | ||
|
|
f31ece3a59 | ||
|
|
cfd08602ab | ||
|
|
4b7152b272 | ||
|
|
5117a66c81 | ||
|
|
83794d4bbc | ||
|
|
76f74778b4 | ||
|
|
ded3425e31 | ||
|
|
738b379fe5 | ||
|
|
cf8b28441f | ||
|
|
0eb5897185 | ||
|
|
25cd1601a6 | ||
|
|
42e4d110ad | ||
|
|
2538f34892 | ||
|
|
3ce11f4cc7 | ||
|
|
f2cd34a79e | ||
|
|
5f923ad485 | ||
|
|
8f70f085d3 | ||
|
|
d6c09ed31a | ||
|
|
7d3ee1331d | ||
|
|
cd5b90a1e2 | ||
|
|
ac861f5fa0 | ||
|
|
c1d8f817bb | ||
|
|
da28a7332b | ||
|
|
bfd4e6a8ed | ||
|
|
b4e0e4b6b2 | ||
|
|
e37caf5c8f | ||
|
|
e95cf24af7 | ||
|
|
524a72caa0 | ||
|
|
1919c562cc | ||
|
|
62b54d6e75 | ||
|
|
efa9160c04 | ||
|
|
bc6955055a | ||
|
|
dc997d5ff2 | ||
|
|
a32f495038 | ||
|
|
210466883c | ||
|
|
728385b70a | ||
|
|
792aa0b922 | ||
|
|
6847b74095 | ||
|
|
54e86b421c | ||
|
|
370666cb0e | ||
|
|
e17f7df930 | ||
|
|
0e91df7acc | ||
|
|
ad26230da5 | ||
|
|
a103f34230 | ||
|
|
806bd3b248 | ||
|
|
c69c39fa44 | ||
|
|
b6badb44af | ||
|
|
b2195ce13f | ||
|
|
f3cb9b8510 | ||
|
|
8edfecb9dc | ||
|
|
c123d103bb | ||
|
|
b92d9da387 | ||
|
|
8841698aab | ||
|
|
6f140f16cd | ||
|
|
8bfd31997b | ||
|
|
4a1459d708 | ||
|
|
361bdeb2b2 | ||
|
|
9ce5af7cd0 | ||
|
|
84fa9e6e7c | ||
|
|
36916ed5c8 | ||
|
|
fb366d3e0b | ||
|
|
6e7670f667 | ||
|
|
e82be8b6a5 | ||
|
|
07320af4ee | ||
|
|
73eb270237 | ||
|
|
222684cfc8 | ||
|
|
3974d2123e | ||
|
|
b837a63b34 | ||
|
|
461316713a | ||
|
|
185af3210b | ||
|
|
e4620b5469 | ||
|
|
5c4acd17a0 | ||
|
|
fc171e5b89 | ||
|
|
662faf2512 | ||
|
|
2fb8af9a4f | ||
|
|
017d03713b | ||
|
|
5f5180d937 | ||
|
|
6b3e6cd6f5 | ||
|
|
f95f3c7b1b | ||
|
|
316b62083c | ||
|
|
530b63f299 | ||
|
|
2f228de163 | ||
|
|
e5e64b25fe | ||
|
|
2d5dde177c | ||
|
|
ce0ad4ba61 | ||
|
|
ebd7c5d6a4 | ||
|
|
341da273c9 | ||
|
|
73d2a43a95 | ||
|
|
eee18889d6 | ||
|
|
590d7fb717 | ||
|
|
dd28ef7ab6 | ||
|
|
36fb033adc | ||
|
|
4275f25f4a | ||
|
|
30b5633498 | ||
|
|
00545fdc50 | ||
|
|
d80e511b08 | ||
|
|
7313355a83 | ||
|
|
66466dc865 | ||
|
|
8cd8df4b02 | ||
|
|
dd7454d38e | ||
|
|
f7c3ed280a | ||
|
|
9ffeb7afe8 | ||
|
|
a83994af43 | ||
|
|
8345034fcd | ||
|
|
a763d3c353 | ||
|
|
5ba5d2755b | ||
|
|
d6bcb8c43d | ||
|
|
2aa2064a67 | ||
|
|
f403d12073 | ||
|
|
b66c2f67da | ||
|
|
d084a4cd81 | ||
|
|
5d2bf56493 | ||
|
|
cd88f5c833 | ||
|
|
ab41e25071 | ||
|
|
eb775da7d4 | ||
|
|
7bc2695da4 | ||
|
|
75fff426bc | ||
|
|
4172df4d78 | ||
|
|
01856b61ef | ||
|
|
2e32559132 | ||
|
|
9adb49df78 | ||
|
|
18e21b0a8e | ||
|
|
e1d7d0e141 | ||
|
|
cfa40e640b | ||
|
|
cb0a45bc17 | ||
|
|
c7b6e5bf24 | ||
|
|
a9ca1b71eb | ||
|
|
97f07bc72d | ||
|
|
8753875d93 | ||
|
|
3692aa80a4 | ||
|
|
b8b09ded5d | ||
|
|
5b8d8b9e55 | ||
|
|
e3fbf4fc77 | ||
|
|
8d680992b7 | ||
|
|
01247f73f4 | ||
|
|
6a7a3dcb90 | ||
|
|
2fbfbb4eb6 | ||
|
|
f88b5d2733 | ||
|
|
363358aaa1 | ||
|
|
7444eeba2a | ||
|
|
e9d686a4c1 | ||
|
|
939ba1bb47 | ||
|
|
d5de868eb9 | ||
|
|
6e3bb6c3a0 | ||
|
|
d347ec420c | ||
|
|
a011b677ea | ||
|
|
8831436809 | ||
|
|
1ededc1f64 | ||
|
|
183c94fd0a | ||
|
|
8629599f86 | ||
|
|
a0a5568d93 | ||
|
|
d166ae5a8b | ||
|
|
145d139e3a | ||
|
|
d3ce34ee31 | ||
|
|
fd61d4431f | ||
|
|
93417d1b37 | ||
|
|
ca3ea36a83 | ||
|
|
c59d9bbf57 | ||
|
|
0cf1cd10c0 | ||
|
|
1da73d1754 | ||
|
|
24037f8366 | ||
|
|
91b891513f | ||
|
|
e7d1f1574f | ||
|
|
80a3a26af8 | ||
|
|
9905ea5a12 | ||
|
|
a7a77cd491 | ||
|
|
f795b1447f | ||
|
|
e5e12bfb61 | ||
|
|
6a8baf08ed | ||
|
|
10ac34a9f7 | ||
|
|
72af1cc2a2 | ||
|
|
cd32ae2a35 | ||
|
|
ddc0c9c6f3 | ||
|
|
489c2a2a9f | ||
|
|
320e81719b | ||
|
|
66a8471f05 | ||
|
|
c7a4ef4722 | ||
|
|
1673ea81df | ||
|
|
306956a7be | ||
|
|
bfe3d38ecc | ||
|
|
6e5bb58f65 | ||
|
|
b96c6c10f8 | ||
|
|
afedfdd596 | ||
|
|
3a7099feb4 | ||
|
|
c704d222f0 | ||
|
|
83ce528e2f | ||
|
|
9cc15f9beb | ||
|
|
d323244157 | ||
|
|
56d35c65bb | ||
|
|
15eabfc834 | ||
|
|
11e8c46e44 | ||
|
|
a14bd78415 | ||
|
|
609f7d09fc | ||
|
|
4c21cb4ba7 | ||
|
|
00ebf45605 | ||
|
|
387777972b | ||
|
|
b7569982ff | ||
|
|
d6be88b61d | ||
|
|
8e454a0419 | ||
|
|
f8932e14c0 | ||
|
|
812bf9b25a | ||
|
|
0d591d5350 | ||
|
|
c9712af73e | ||
|
|
da483706b1 | ||
|
|
4b600cb190 | ||
|
|
25a56a22fa | ||
|
|
4e81f0949c | ||
|
|
18e79cf516 | ||
|
|
fad0a6070c | ||
|
|
755fcfeef2 | ||
|
|
40739b598b | ||
|
|
9782503d1d | ||
|
|
35ced9b9ad | ||
|
|
9b28c0a1d1 | ||
|
|
fd19c5be58 | ||
|
|
58b13e233c | ||
|
|
ce55066208 | ||
|
|
7d582d2422 | ||
|
|
fe1d553a8d | ||
|
|
99c05a44f5 | ||
|
|
678360953d | ||
|
|
9867e81220 | ||
|
|
49cfc3c044 | ||
|
|
43ae15b71c | ||
|
|
1c2df71e0f | ||
|
|
a806ec27db | ||
|
|
14bd2e22fc | ||
|
|
f94728bf67 | ||
|
|
caeaf1774e | ||
|
|
1388b40a6b | ||
|
|
e44d5f644c | ||
|
|
fe9fd3024e | ||
|
|
b664e35b11 | ||
|
|
a77a31121f | ||
|
|
381de6b554 | ||
|
|
13bd727b3e | ||
|
|
9021291aef | ||
|
|
8bd7ab13d0 | ||
|
|
8eefd94569 | ||
|
|
b3b2baf0e4 | ||
|
|
836380048a | ||
|
|
f105aaa567 | ||
|
|
6238d66ca2 | ||
|
|
7e325a7eb6 | ||
|
|
c91446c5ac | ||
| eaf4cd773d | |||
| 8950482bac | |||
|
|
b615446274 | ||
|
|
f276735b5c | ||
|
|
31aa5829f6 | ||
| 27a5538229 | |||
| 322fb2fd7e | |||
| 8e33094806 | |||
| 54b246f8e4 | |||
|
|
5c51ea679e | ||
|
|
e264a10a36 | ||
| 2f8aed8640 | |||
| 29eac347c3 | |||
|
|
dd6ab13e6e | ||
|
|
d94d9f045e | ||
|
|
12bfcb1f25 | ||
|
|
63613f2073 | ||
|
|
1c11a0e8f0 | ||
|
|
d376065246 | ||
|
|
4166dfde4b | ||
|
|
1bc43a5a77 | ||
|
|
33f4c6e489 | ||
|
|
a4b880f1d2 | ||
| a7f38eafb2 | |||
| 67a8506a37 | |||
|
|
ecec1e1206 | ||
|
|
854ed45abd | ||
|
|
c0cece62af | ||
|
|
408969d6dd | ||
|
|
9e019c0b69 | ||
|
|
2f4ffac9c4 | ||
|
|
6464a591a8 | ||
|
|
56df8234c7 | ||
|
|
95958f2a1d | ||
|
|
39cc257466 | ||
|
|
c4a66ee5bb | ||
|
|
cc3f6efbd7 | ||
|
|
c0a6103eb2 | ||
|
|
79bb454fd1 | ||
|
|
fc91a451f6 | ||
|
|
1efd241ab0 | ||
|
|
e8ff922726 | ||
|
|
8f3e72ae8b | ||
|
|
9279f8e79a | ||
|
|
1b2a316e5f | ||
|
|
36d305a1e8 | ||
|
|
963a36acfa | ||
|
|
30ee71eaf5 | ||
|
|
5f161d81f2 | ||
|
|
4d040959a5 | ||
|
|
5846a7433c | ||
|
|
2f41a993ee | ||
|
|
eac7454989 | ||
|
|
8c767a73b4 | ||
|
|
9e33fc1d96 | ||
|
|
23bf7579f6 | ||
|
|
13b9394073 | ||
|
|
af27163b08 | ||
|
|
155726a6b0 | ||
|
|
9f8142a5d6 | ||
|
|
0f97c325cf | ||
|
|
7961fcbf0f | ||
|
|
a1d251d705 | ||
|
|
07ad18eccb | ||
|
|
bf23fceb6b | ||
|
|
2dc860b923 | ||
|
|
9b2c5d9ca5 | ||
|
|
76bfb895a9 | ||
|
|
38aa6a6217 | ||
|
|
0268756cf9 | ||
|
|
f509cc8b3b | ||
|
|
290a1dd522 | ||
|
|
2c147f44b7 | ||
|
|
3fd2f90f65 | ||
|
|
d077a66796 | ||
|
|
f16a8bcdb9 | ||
|
|
33f161a5fe | ||
|
|
7697939d7e | ||
|
|
34b3c46720 | ||
|
|
65618e5df9 | ||
|
|
8d5493969f | ||
|
|
0818b8d606 | ||
|
|
047c4d09e8 | ||
|
|
26f2e157c6 | ||
|
|
f26f400937 | ||
|
|
0e4cfc452f | ||
|
|
95b80a650c | ||
|
|
f4dd17fca9 | ||
|
|
e4aed5309e | ||
|
|
c31f081208 | ||
| 76d4151182 | |||
| df2537bf29 | |||
| 5ca4c04669 | |||
| 297ecfab7b | |||
| 48db26931c | |||
|
|
21934928c2 | ||
|
|
21e8a86a99 | ||
|
|
0228e82c63 | ||
|
|
50247517b9 | ||
|
|
1357b714cf | ||
|
|
88da8e4ace | ||
|
|
89290c03f9 | ||
|
|
3b27260b14 | ||
|
|
9fa5827b09 | ||
|
|
3448c17d8b | ||
|
|
48ec83161d | ||
|
|
cc63b24947 | ||
|
|
c3db8d0d00 | ||
|
|
037ebfbe5c | ||
|
|
42258cbbb8 | ||
|
|
4c96274084 | ||
|
|
b594ddb646 | ||
|
|
b60ae62779 | ||
|
|
7863e861c7 | ||
|
|
2014f6149d | ||
|
|
60afdc23da | ||
|
|
90ac81c576 | ||
|
|
8d6d483c5d | ||
|
|
824bf6fb82 | ||
|
|
0c6fd2efe3 | ||
|
|
1f4cf54406 | ||
|
|
a6635f4a20 | ||
|
|
ed25482cee | ||
|
|
1664b5739e | ||
|
|
0ef9d3c49e | ||
|
|
86bdb233c2 | ||
|
|
bc6972bcfb | ||
|
|
2e66129485 | ||
|
|
81220ac9b4 | ||
|
|
d7252ce888 | ||
|
|
ba723bdddb | ||
|
|
68714c2937 | ||
|
|
cf9286e4c3 | ||
|
|
87a766a2e8 | ||
|
|
674d753735 | ||
|
|
c688a42e45 | ||
|
|
db83f25d57 | ||
|
|
ef6e921451 | ||
|
|
dd18094deb | ||
|
|
4f61f1b6cb | ||
|
|
efcd254749 | ||
|
|
357866ea44 | ||
|
|
d8617093ce | ||
|
|
b19cccdc34 | ||
|
|
79aa6f4cb3 | ||
|
|
a285a0b9c2 | ||
|
|
84442410a5 | ||
|
|
22a3ec914d | ||
|
|
9620cb7189 | ||
|
|
eb096cb201 | ||
|
|
cc01f57125 | ||
| a7cf500858 | |||
| b24f06509e | |||
|
|
6b3c90c618 | ||
|
|
966b7de3c4 | ||
|
|
8efe321cc7 | ||
|
|
6338b81571 | ||
| 0582e7e002 | |||
| 3f40b9449b | |||
| fd694b2cee | |||
| d4a9eba6ab | |||
|
|
f2e718565d | ||
|
|
f7b11e3427 | ||
|
|
74cb595128 | ||
|
|
23609d2bd7 | ||
|
|
1c55c4aa99 | ||
|
|
87c839549a | ||
| 02d883dfbf | |||
| f51c500f90 | |||
|
|
49cfeb28d9 | ||
|
|
5e758899ab | ||
|
|
f5dd3cf8be | ||
|
|
2c17d440c0 | ||
|
|
6941a3db8d | ||
|
|
1584fd6f1c | ||
|
|
2512de0f26 | ||
|
|
db83eb90ee | ||
|
|
501d48961e | ||
|
|
ab713a23ac | ||
|
|
cbb03d77ba | ||
|
|
29ae546d98 | ||
|
|
8de0d70e7b | ||
|
|
b43b1ef866 | ||
|
|
b8d4abb7b2 | ||
|
|
b65766ce24 | ||
| 83746abb1b | |||
| c14ed86181 | |||
| 56eb385312 | |||
| 5abc1d9779 | |||
|
|
6fc210132d | ||
| a3c66ecd19 | |||
| a25b517445 | |||
|
|
181ee67bab | ||
|
|
c459828706 | ||
|
|
6f59906a7e | ||
| 21baf0bad0 | |||
| 47f924ad7e | |||
| a2b0682a77 | |||
| 86d9bd185a | |||
| 0064eee9d5 | |||
| d4aa3ec82e | |||
| 55f2a6a775 | |||
| 4cd39c6c5c | |||
| 51741be5de | |||
| 31ca8b8b9e | |||
| dd55e2a2d9 | |||
|
|
02a197e535 | ||
|
|
ddd0808f41 | ||
|
|
c504567c41 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -360,4 +360,6 @@ MigrationBackup/
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
FodyWeavers.xsd
|
||||
/EnvelopeGenerator.Web/.config/dotnet-tools.json
|
||||
/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/.vscode
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace EnvelopeGenerator.Application.Configurations
|
||||
{
|
||||
public class AuthenticatorParams
|
||||
{
|
||||
public string CharPool { get; init; } = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789012345678901234567890123456789";
|
||||
|
||||
//TODO: Increase the DefaultTotpSecretKeyLength (e.g. to 32) but make sure that the QR code is generated correctly and can be scanned by the authenticator.
|
||||
public int DefaultTotpSecretKeyLength { get; init; } = 20;
|
||||
|
||||
public string TotpIssuer { get; init; } = "signFlow";
|
||||
|
||||
/// <summary>
|
||||
/// 0 is user email, 1 is secret key and 2 is issuer.
|
||||
/// </summary>
|
||||
public string TotpUrlFormat { get; init; } = "otpauth://totp/{0}?secret={1}&issuer={2}";
|
||||
|
||||
public int TotpQRPixelsPerModule { get; init; } = 20;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace EnvelopeGenerator.Application.Configurations;
|
||||
|
||||
public class DispatcherParams
|
||||
{
|
||||
public int SendingProfile { get; init; } = 1;
|
||||
|
||||
public string AddedWho { get; init; } = "DDEnvelopGenerator";
|
||||
|
||||
public int ReminderTypeId { get; init; } = 202377;
|
||||
|
||||
public string EmailAttmt1 { get; init; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using DigitalData.Core.Abstractions.Client;
|
||||
namespace EnvelopeGenerator.Application.Configurations;
|
||||
|
||||
/// <summary>
|
||||
/// https://www.gtx-messaging.com/en/api-docs/sms-rest-api/
|
||||
/// </summary>
|
||||
public class GtxMessagingParams : IHttpClientOptions
|
||||
{
|
||||
public required string Uri { get; init; }
|
||||
|
||||
public string? Path { get; init; }
|
||||
|
||||
public Dictionary<string, object>? Headers { get; init; }
|
||||
|
||||
public Dictionary<string, object?>? QueryParams { get; init; }
|
||||
|
||||
public string RecipientQueryParamName { get; init; } = "to";
|
||||
|
||||
public string MessageQueryParamName { get; init; } = "text";
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace EnvelopeGenerator.Application.Configurations;
|
||||
|
||||
public class MailParams
|
||||
{
|
||||
public required Dictionary<string, string> Placeholders { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using OtpNet;
|
||||
using System.Globalization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Configurations
|
||||
{
|
||||
public class TotpSmsParams
|
||||
{
|
||||
/// <summary>
|
||||
/// The unit is second.
|
||||
/// </summary>
|
||||
public int TotpStep { get; init; } = 90;
|
||||
|
||||
public string Format { get; init; } = "Ihr 2FA-Passwort lautet {0}. Gültig bis {1}";
|
||||
|
||||
public ExpirationHandler Expiration { get; init; } = new();
|
||||
|
||||
public VerificationWindow? TotpVerificationWindow { get; private init; } = VerificationWindow.RfcSpecifiedNetworkDelay;
|
||||
|
||||
private IEnumerable<int>? _tvwParams;
|
||||
|
||||
public IEnumerable<int>? TotpVerificationWindowParams
|
||||
{
|
||||
get => _tvwParams;
|
||||
init
|
||||
{
|
||||
_tvwParams = value;
|
||||
if(_tvwParams is not null)
|
||||
TotpVerificationWindow = new(previous: _tvwParams.ElementAtOrDefault(0), future: _tvwParams.ElementAtOrDefault(0));
|
||||
}
|
||||
}
|
||||
|
||||
public class ExpirationHandler
|
||||
{
|
||||
public string CacheKeyFormat { get; init; } = "e{0}_r{1}_sms_code_expiration";
|
||||
|
||||
public string Format { get; init; } = "HH:mm:ss";
|
||||
|
||||
public string CultureName
|
||||
{
|
||||
get => _cultureInfo.Name;
|
||||
init => _cultureInfo = new(value);
|
||||
}
|
||||
|
||||
private CultureInfo _cultureInfo = new("de-DE");
|
||||
|
||||
public CultureInfo CultureInfo => _cultureInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
EnvelopeGenerator.Application/Contracts/IAuthenticator.cs
Normal file
19
EnvelopeGenerator.Application/Contracts/IAuthenticator.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using OtpNet;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IAuthenticator
|
||||
{
|
||||
string GenerateCode(int length);
|
||||
|
||||
string GenerateTotpSecretKey(int? length = null);
|
||||
|
||||
byte[] GenerateTotpQrCode(string userEmail, string secretKey, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null);
|
||||
|
||||
byte[] GenerateTotpQrCode(string userEmail, int? length = null, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null);
|
||||
|
||||
string GenerateTotp(string secretKey, int step = 30);
|
||||
|
||||
bool VerifyTotp(string totpCode, string secretKey, int step = 30, VerificationWindow? window = null);
|
||||
}
|
||||
}
|
||||
17
EnvelopeGenerator.Application/Contracts/IConfigService.cs
Normal file
17
EnvelopeGenerator.Application/Contracts/IConfigService.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IConfigService : IReadService<ConfigDto, Config, int>
|
||||
{
|
||||
Task<DataResult<ConfigDto>> ReadFirstAsync();
|
||||
|
||||
Task<ConfigDto> ReadDefaultAsync();
|
||||
|
||||
Task<string> ReadDefaultSignatureHost();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IDocumentReceiverElementService : IBasicCRUDService<DocumentReceiverElementDto, DocumentReceiverElement, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IDocumentStatusService : IBasicCRUDService<DocumentStatusDto, DocumentStatus, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEmailTemplateService : IBasicCRUDService<EmailTemplateDto, EmailTemplate, int>
|
||||
{
|
||||
Task<DataResult<EmailTemplateDto>> ReadByNameAsync(EmailTemplateType type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeCertificateService : IBasicCRUDService<EnvelopeCertificateDto, EnvelopeCertificate, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeDocumentService : IBasicCRUDService<EnvelopeDocumentDto, EnvelopeDocument, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeHistoryService : ICRUDService<EnvelopeHistoryCreateDto, EnvelopeHistoryDto, EnvelopeHistoryDto, EnvelopeHistory, long>
|
||||
{
|
||||
Task<int> CountAsync(int? envelopeId = null, string? userReference = null, int? status = null);
|
||||
|
||||
Task<bool> AccessCodeAlreadyRequested(int envelopeId, string userReference);
|
||||
|
||||
Task<bool> IsSigned(int envelopeId, string userReference);
|
||||
|
||||
Task<bool> IsRejected(int envelopeId, string? userReference = null);
|
||||
|
||||
Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null, bool withSender = false, bool withReceiver = false);
|
||||
|
||||
Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null);
|
||||
|
||||
Task<IEnumerable<ReceiverReadDto>> ReadRejectingReceivers(int envelopeId);
|
||||
|
||||
Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Common;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeMailService : IEmailOutService
|
||||
{
|
||||
Task<DataResult<int>> SendAsync(EnvelopeReceiverDto envelopeReceiverDto, Constants.EmailTemplateType tempType, Dictionary<string, object>? optionalPlaceholders = null);
|
||||
|
||||
Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto, Dictionary<string, object>? optionalPlaceholders = null);
|
||||
|
||||
Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto envelopeReceiverDto);
|
||||
|
||||
Task<DataResult<int>> SendTFAQrCodeAsync(EnvelopeReceiverDto envelopeReceiverDto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeReceiverReadOnlyService : ICRUDService<EnvelopeReceiverReadOnlyCreateDto, EnvelopeReceiverReadOnlyDto, EnvelopeReceiverReadOnlyUpdateDto, EnvelopeReceiverReadOnly, long>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeReceiverService : IBasicCRUDService<EnvelopeReceiverDto, EnvelopeReceiver, (int Envelope, int Receiver)>
|
||||
{
|
||||
|
||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false, bool readOnly = true);
|
||||
|
||||
Task<DataResult<IEnumerable<string?>>> ReadAccessCodeByUuidAsync(string uuid, bool withEnvelope = false, bool withReceiver = true);
|
||||
|
||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true, bool readOnly = true);
|
||||
|
||||
Task<DataResult<EnvelopeReceiverDto>> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true, bool readOnly = true);
|
||||
|
||||
Task<DataResult<EnvelopeReceiverSecretDto>> ReadWithSecretByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true, bool readOnly = true);
|
||||
|
||||
Task<DataResult<EnvelopeReceiverDto>> ReadByEnvelopeReceiverIdAsync(string envelopeReceiverId, bool withEnvelope = true, bool withReceiver = true, bool readOnly = true);
|
||||
|
||||
Task<DataResult<string>> ReadAccessCodeByIdAsync(int envelopeId, int receiverId);
|
||||
|
||||
Task<DataResult<bool>> VerifyAccessCodeAsync(string uuid, string signature, string accessCode);
|
||||
|
||||
Task<DataResult<bool>> VerifyAccessCodeAsync(string envelopeReceiverId, string accessCode);
|
||||
|
||||
Task<DataResult<bool>> IsExisting(string envelopeReceiverId);
|
||||
|
||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
||||
|
||||
Task<DataResult<string?>> ReadLastUsedReceiverNameByMail(string mail);
|
||||
|
||||
Task<DataResult<SmsResponse>> SendSmsAsync(string envelopeReceiverId, string message);
|
||||
}
|
||||
}
|
||||
16
EnvelopeGenerator.Application/Contracts/IEnvelopeService.cs
Normal file
16
EnvelopeGenerator.Application/Contracts/IEnvelopeService.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeService : IBasicCRUDService<EnvelopeDto, Envelope, int>
|
||||
{
|
||||
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false);
|
||||
|
||||
Task<DataResult<EnvelopeDto>> ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false);
|
||||
|
||||
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[]ignore_statuses);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts;
|
||||
|
||||
public interface IEnvelopeSmsHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// If expiration is passed then, sends sms and returns smsResponse and up-to-date expiration; otherwise send expiration.
|
||||
/// </summary>
|
||||
/// <param name="er_secret"></param>
|
||||
/// <param name="cToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<(SmsResponse? SmsResponse, DateTime Expiration)> SendTotpAsync(EnvelopeReceiverSecretDto er_secret, CancellationToken cToken = default);
|
||||
|
||||
bool VerifyTotp(string totpCode, string secretKey);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeTypeService : IBasicCRUDService<EnvelopeTypeDto, EnvelopeType, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
17
EnvelopeGenerator.Application/Contracts/IReceiverService.cs
Normal file
17
EnvelopeGenerator.Application/Contracts/IReceiverService.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IReceiverService : ICRUDService<ReceiverCreateDto, ReceiverReadDto, ReceiverUpdateDto, Receiver, int>
|
||||
{
|
||||
Task<DataResult<ReceiverReadDto>> ReadByAsync(string? emailAddress = null, string? signature = null);
|
||||
|
||||
Task<Result> DeleteByAsync(string? emailAddress = null, string? signature = null);
|
||||
|
||||
Task<Result> UpdateAsync<TUpdateDto>(TUpdateDto updateDto) where TUpdateDto : IUnique<int>;
|
||||
}
|
||||
}
|
||||
11
EnvelopeGenerator.Application/Contracts/ISmsSender.cs
Normal file
11
EnvelopeGenerator.Application/Contracts/ISmsSender.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts;
|
||||
|
||||
//TODO: move to DigitalData.Core
|
||||
public interface ISmsSender
|
||||
{
|
||||
string ServiceProvider { get; }
|
||||
|
||||
Task<SmsResponse> SendSmsAsync(string recipient, string message);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using DigitalData.Core.Abstractions.Application;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IUserReceiverService : IBasicCRUDService<UserReceiverDto, UserReceiver, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
19
EnvelopeGenerator.Application/DTOs/ConfigDto.cs
Normal file
19
EnvelopeGenerator.Application/DTOs/ConfigDto.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record ConfigDto(
|
||||
string DocumentPath,
|
||||
int SendingProfile,
|
||||
string SignatureHost,
|
||||
string ExternalProgramName,
|
||||
string ExportPath) : IUnique<int>
|
||||
{
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
[Obsolete("Configuration does not have an ID; it represents a single table in the database.")]
|
||||
public int Id => throw new InvalidOperationException("This configuration does not support an ID as it represents a single row in the database.");
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record DocumentReceiverElementDto(
|
||||
int Id,
|
||||
int DocumentId,
|
||||
int ReceiverId,
|
||||
int ElementType,
|
||||
double X,
|
||||
double Y,
|
||||
double Width,
|
||||
double Height,
|
||||
int Page,
|
||||
bool Required,
|
||||
string? Tooltip,
|
||||
bool ReadOnly,
|
||||
int AnnotationIndex,
|
||||
DateTime AddedWhen,
|
||||
DateTime? ChangedWhen,
|
||||
double Top,
|
||||
double Left
|
||||
): IUnique<int>;
|
||||
}
|
||||
14
EnvelopeGenerator.Application/DTOs/DocumentStatusDto.cs
Normal file
14
EnvelopeGenerator.Application/DTOs/DocumentStatusDto.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record DocumentStatusDto(
|
||||
int Id,
|
||||
int EnvelopeId,
|
||||
int ReceiverId,
|
||||
int Status,
|
||||
DateTime? StatusChangedWhen,
|
||||
string Value,
|
||||
DateTime AddedWhen,
|
||||
DateTime? ChangedWhen) : IUnique<int>;
|
||||
}
|
||||
10
EnvelopeGenerator.Application/DTOs/EmailTemplateDto.cs
Normal file
10
EnvelopeGenerator.Application/DTOs/EmailTemplateDto.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record EmailTemplateDto(
|
||||
int Id,
|
||||
string Name,
|
||||
string Body,
|
||||
string Subject) : IUnique<int>;
|
||||
}
|
||||
14
EnvelopeGenerator.Application/DTOs/EnvelopeCertificateDto.cs
Normal file
14
EnvelopeGenerator.Application/DTOs/EnvelopeCertificateDto.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record EnvelopeCertificateDto(
|
||||
int Id,
|
||||
int EnvelopeId,
|
||||
string EnvelopeUuid,
|
||||
string EnvelopeSubject,
|
||||
int CreatorId,
|
||||
string CreatorName,
|
||||
string CreatorEmail,
|
||||
int EnvelopeStatus) : IUnique<int>;
|
||||
}
|
||||
13
EnvelopeGenerator.Application/DTOs/EnvelopeDocumentDto.cs
Normal file
13
EnvelopeGenerator.Application/DTOs/EnvelopeDocumentDto.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record EnvelopeDocumentDto
|
||||
(
|
||||
int Id,
|
||||
int EnvelopeId,
|
||||
DateTime AddedWhen,
|
||||
byte[]? ByteData = null,
|
||||
IEnumerable<DocumentReceiverElementDto>? Elements = null
|
||||
) : IUnique<int>;
|
||||
}
|
||||
69
EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs
Normal file
69
EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record EnvelopeDto() : IUnique<int>
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
public int Status { get; set; }
|
||||
|
||||
public string StatusName { get; set; }
|
||||
|
||||
public string Uuid { get; set; }
|
||||
|
||||
[TemplatePlaceholder("[MESSAGE]")]
|
||||
public string Message { get; set; }
|
||||
public DateTime? ExpiresWhen { get; set; }
|
||||
public DateTime? ExpiresWarningWhen { get; set; }
|
||||
public DateTime AddedWhen { get; set; }
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
|
||||
[TemplatePlaceholder("[DOCUMENT_TITLE]")]
|
||||
public string Title { get; set; }
|
||||
|
||||
public int? ContractType { get; set; }
|
||||
|
||||
public string Language { get; set; }
|
||||
|
||||
public bool? SendReminderEmails { get; set; }
|
||||
|
||||
public int? FirstReminderDays { get; set; }
|
||||
|
||||
public int? ReminderIntervalDays { get; set; }
|
||||
|
||||
public int? EnvelopeTypeId { get; set; }
|
||||
|
||||
public int? CertificationType { get; set; }
|
||||
|
||||
public bool? UseAccessCode { get; set; }
|
||||
|
||||
public int? FinalEmailToCreator { get; set; }
|
||||
|
||||
public int? FinalEmailToReceivers { get; set; }
|
||||
|
||||
public int? ExpiresWhenDays { get; set; }
|
||||
|
||||
public int? ExpiresWarningWhenDays { get; set; }
|
||||
|
||||
public bool TFAEnabled { get; init; }
|
||||
|
||||
public bool DmzMoved { get; set; }
|
||||
public UserReadDto? User { get; set; }
|
||||
public EnvelopeType? EnvelopeType { get; set; }
|
||||
|
||||
public string? EnvelopeTypeTitle { get; set; }
|
||||
|
||||
public bool IsAlreadySent { get; set; }
|
||||
|
||||
public string? StatusTranslated { get; set; }
|
||||
|
||||
public string? ContractTypeTranslated { get; set; }
|
||||
public IEnumerable<EnvelopeDocumentDto>? Documents { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
|
||||
{
|
||||
public record EnvelopeHistoryCreateDto(
|
||||
int EnvelopeId,
|
||||
string UserReference,
|
||||
int Status,
|
||||
DateTime? ActionDate,
|
||||
string? Comment = null);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
|
||||
{
|
||||
public record EnvelopeHistoryDto(
|
||||
long Id,
|
||||
int EnvelopeId,
|
||||
string UserReference,
|
||||
int Status,
|
||||
string? StatusName,
|
||||
DateTime AddedWhen,
|
||||
DateTime? ActionDate,
|
||||
UserCreateDto? Sender,
|
||||
ReceiverReadDto? Receiver,
|
||||
ReferenceType ReferenceType,
|
||||
string? Comment = null) : BaseDTO<long>(Id), IUnique<long>;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver
|
||||
{
|
||||
public record EnvelopeReceiverBasicDto() : IUnique<(int Envelope, int Receiver)>
|
||||
{
|
||||
public (int Envelope, int Receiver) Id => (Envelope: EnvelopeId, Receiver: ReceiverId);
|
||||
|
||||
public int EnvelopeId { get; init; }
|
||||
|
||||
public int ReceiverId { get; init; }
|
||||
|
||||
public int Sequence { get; init; }
|
||||
|
||||
[TemplatePlaceholder("[NAME_RECEIVER]")]
|
||||
public string? Name { get; init; }
|
||||
|
||||
public string? JobTitle { get; init; }
|
||||
|
||||
public string? CompanyName { get; init; }
|
||||
|
||||
public string? PrivateMessage { get; init; }
|
||||
|
||||
public DateTime AddedWhen { get; init; }
|
||||
|
||||
public DateTime? ChangedWhen { get; init; }
|
||||
|
||||
public bool HasPhoneNumber { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver
|
||||
{
|
||||
public record EnvelopeReceiverDto() : EnvelopeReceiverBasicDto()
|
||||
{
|
||||
public EnvelopeDto? Envelope { get; set; }
|
||||
|
||||
public ReceiverReadDto? Receiver { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver
|
||||
{
|
||||
public record EnvelopeReceiverSecretDto() : EnvelopeReceiverDto()
|
||||
{
|
||||
public string? AccessCode { get; init; }
|
||||
|
||||
public string? PhoneNumber { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly
|
||||
{
|
||||
public record EnvelopeReceiverReadOnlyCreateDto(
|
||||
DateTime DateValid)
|
||||
{
|
||||
[EmailAddress]
|
||||
[Required]
|
||||
public required string ReceiverMail { get; init; }
|
||||
|
||||
[JsonIgnore]
|
||||
public long? EnvelopeId { get; set; } = null;
|
||||
|
||||
[JsonIgnore]
|
||||
public string? AddedWho { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public DateTime AddedWhen { get; } = DateTime.Now;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly
|
||||
{
|
||||
public record EnvelopeReceiverReadOnlyDto(
|
||||
long Id,
|
||||
long EnvelopeId,
|
||||
string ReceiverMail,
|
||||
DateTime DateValid,
|
||||
DateTime AddedWhen,
|
||||
string AddedWho,
|
||||
EnvelopeDto? Envelope = null,
|
||||
string? ChangedWho = null,
|
||||
DateTime? ChangedWhen = null,
|
||||
ReceiverReadDto? Receiver = null);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly
|
||||
{
|
||||
public record EnvelopeReceiverReadOnlyUpdateDto(
|
||||
long Id,
|
||||
DateTime DateValid,
|
||||
string ChangedWho) : IUnique<long>
|
||||
{
|
||||
public DateTime ChangedWhen { get; } = DateTime.Now;
|
||||
};
|
||||
}
|
||||
21
EnvelopeGenerator.Application/DTOs/EnvelopeTypeDto.cs
Normal file
21
EnvelopeGenerator.Application/DTOs/EnvelopeTypeDto.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record EnvelopeTypeDto(
|
||||
int Id,
|
||||
string Title,
|
||||
string Language,
|
||||
int? ExpiresDays,
|
||||
int? CertificationType,
|
||||
bool? UseAccessCode,
|
||||
int? FinalEmailToCreator,
|
||||
int? FinalEmailToReceivers,
|
||||
DateTime AddedWhen,
|
||||
DateTime? ChangedWhen,
|
||||
int? ExpiresWarningDays,
|
||||
bool? SendReminderEmails,
|
||||
int? FirstReminderDays,
|
||||
int? ReminderIntervalDays,
|
||||
int? ContractType) : IUnique<int>;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace EnvelopeGenerator.Application.DTOs.Messaging
|
||||
{
|
||||
public class GtxMessagingResponse : Dictionary<string, object?> { }
|
||||
}
|
||||
11
EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs
Normal file
11
EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace EnvelopeGenerator.Application.DTOs.Messaging
|
||||
{
|
||||
public record SmsResponse
|
||||
{
|
||||
public required bool Ok { get; init; }
|
||||
|
||||
public bool Failed => !Ok;
|
||||
|
||||
public dynamic? Errors { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.Receiver
|
||||
{
|
||||
public record ReceiverCreateDto([EmailAddress] string EmailAddress, string? TotpSecretkey = null)
|
||||
{
|
||||
public string Signature => sha256HexOfMail.Value;
|
||||
|
||||
private readonly Lazy<string> sha256HexOfMail = new(() =>
|
||||
{
|
||||
var bytes_arr = Encoding.UTF8.GetBytes(EmailAddress.ToUpper());
|
||||
var hash_arr = SHA256.HashData(bytes_arr);
|
||||
var hexa_str = BitConverter.ToString(hash_arr);
|
||||
return hexa_str.Replace("-", string.Empty);
|
||||
});
|
||||
|
||||
public DateTime AddedWhen { get; } = DateTime.Now;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
|
||||
public record ReceiverReadDto(
|
||||
int Id,
|
||||
string EmailAddress,
|
||||
string Signature,
|
||||
DateTime AddedWhen
|
||||
) : BaseDTO<int>(Id), IUnique<int>
|
||||
{
|
||||
[JsonIgnore]
|
||||
public IEnumerable<EnvelopeReceiverBasicDto>? EnvelopeReceivers { get; init; }
|
||||
|
||||
public string? LastUsedName => EnvelopeReceivers?.LastOrDefault()?.Name;
|
||||
|
||||
public string? TotpSecretkey { get; set; } = null;
|
||||
|
||||
public DateTime? TfaRegDeadline { get; set; }
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
|
||||
public record ReceiverUpdateDto(int Id, string? TotpSecretkey = null, DateTime? TfaRegDeadline = null) : IUnique<int>;
|
||||
13
EnvelopeGenerator.Application/DTOs/UserReceiverDto.cs
Normal file
13
EnvelopeGenerator.Application/DTOs/UserReceiverDto.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using DigitalData.Core.Abstractions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record UserReceiverDto(
|
||||
int Id,
|
||||
int UserId,
|
||||
int ReceiverId,
|
||||
string Name,
|
||||
string CompanyName,
|
||||
string JobTitle,
|
||||
DateTime AddedWhen) : IUnique<int>;
|
||||
}
|
||||
10
EnvelopeGenerator.Application/EnvelopeFlag.cs
Normal file
10
EnvelopeGenerator.Application/EnvelopeFlag.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace EnvelopeGenerator.Application
|
||||
{
|
||||
public enum EnvelopeFlag
|
||||
{
|
||||
EnvelopeOrReceiverNonexists,
|
||||
NonDecodableEnvelopeReceiverId,
|
||||
WrongEnvelopeReceiverId,
|
||||
AccessCodeNull
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Model.Designer.vb" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="2.2.1" />
|
||||
<PackageReference Include="DigitalData.Core.Application" Version="2.0.0" />
|
||||
<PackageReference Include="DigitalData.Core.Client" Version="2.0.3" />
|
||||
<PackageReference Include="DigitalData.Core.DTO" Version="2.0.0" />
|
||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
|
||||
<PackageReference Include="Otp.NET" Version="1.4.0" />
|
||||
<PackageReference Include="QRCoder" Version="1.6.0" />
|
||||
<PackageReference Include="QRCoder-ImageSharp" Version="0.10.0" />
|
||||
<PackageReference Include="UserManager.Application" Version="2.0.0" />
|
||||
<PackageReference Include="UserManager.Infrastructure" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Extensions\EnvelopeGenerator.Extensions.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Resources\Model.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Model.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resources\Model.en.resx">
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<LastGenOutput>Model.en.Designer.vb</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resources\Model.resx">
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<LastGenOutput>Model.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resources\Resource.de-DE.resx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resources\Resource.en-US.resx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
131
EnvelopeGenerator.Application/Extensions/CacheExtensions.cs
Normal file
131
EnvelopeGenerator.Application/Extensions/CacheExtensions.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Extensions
|
||||
{
|
||||
public static class CacheExtensions
|
||||
{
|
||||
public static Task SetLongAsync(this IDistributedCache cache, string key, long value, DistributedCacheEntryOptions? options = null, CancellationToken cToken = default)
|
||||
=> options is null
|
||||
? cache.SetAsync(key, BitConverter.GetBytes(value), token: cToken)
|
||||
: cache.SetAsync(key, BitConverter.GetBytes(value), options: options, token: cToken);
|
||||
|
||||
public static async Task<long?> GetLongAsync(this IDistributedCache cache, string key, CancellationToken cToken = default)
|
||||
{
|
||||
var value = await cache.GetAsync(key, cToken);
|
||||
return value is null ? null : BitConverter.ToInt64(value, 0);
|
||||
}
|
||||
|
||||
public static Task SetDateTimeAsync(this IDistributedCache cache, string key, DateTime value, DistributedCacheEntryOptions? options = null, CancellationToken cToken = default)
|
||||
=> cache.SetLongAsync(key: key, value: value.Ticks, options: options, cToken: cToken);
|
||||
|
||||
public static async Task<DateTime?> GetDateTimeAsync(this IDistributedCache cache, string key, CancellationToken cToken = default)
|
||||
{
|
||||
var value = await cache.GetAsync(key, cToken);
|
||||
return value is null ? null : new(BitConverter.ToInt64(value, 0));
|
||||
}
|
||||
|
||||
public static Task SetTimeSpanAsync(this IDistributedCache cache, string key, TimeSpan value, DistributedCacheEntryOptions? options = null, CancellationToken cToken = default)
|
||||
=> cache.SetLongAsync(key: key, value: value.Ticks, options: options, cToken);
|
||||
|
||||
public static async Task<TimeSpan?> GetTimeSpanAsync(this IDistributedCache cache, string key, CancellationToken cToken = default)
|
||||
{
|
||||
var value = await cache.GetAsync(key, cToken);
|
||||
return value is null ? null : new(BitConverter.ToInt64(value, 0));
|
||||
}
|
||||
|
||||
//TODO: use code generator
|
||||
#region GetOrSetAsync
|
||||
|
||||
#region string
|
||||
public static async Task<string> GetOrSetAsync(this IDistributedCache cache, string key, Func<string> factory, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken cToken = default)
|
||||
{
|
||||
var value = await cache.GetStringAsync(key, cToken);
|
||||
if (value is null)
|
||||
{
|
||||
// create new and save
|
||||
value = factory();
|
||||
|
||||
Task CacheAsync() => options is null
|
||||
? cache.SetStringAsync(key, value, cToken)
|
||||
: cache.SetStringAsync(key, value, options, cToken);
|
||||
|
||||
if (cacheInBackground)
|
||||
_ = Task.Run(async () => await CacheAsync(), cToken);
|
||||
else
|
||||
await CacheAsync();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async Task<string> GetOrSetAsync(this IDistributedCache cache, string key, Func<Task<string>> factoryAsync, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken cToken = default)
|
||||
{
|
||||
var value = await cache.GetStringAsync(key, cToken);
|
||||
if(value is null)
|
||||
{
|
||||
// create new and save
|
||||
value = await factoryAsync();
|
||||
|
||||
Task CacheAsync() => options is null
|
||||
? cache.SetStringAsync(key: key, value: value, token: cToken)
|
||||
: cache.SetStringAsync(key: key, value: value, options: options, token: cToken);
|
||||
|
||||
if (cacheInBackground)
|
||||
_ = Task.Run(async () => await CacheAsync(), cToken);
|
||||
else
|
||||
await CacheAsync();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DateTime
|
||||
public static async Task<DateTime> GetOrSetAsync(this IDistributedCache cache, string key, Func<DateTime> factory, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken cToken = default)
|
||||
{
|
||||
if (await cache.GetDateTimeAsync(key, cToken) is DateTime dateTimeValue)
|
||||
return dateTimeValue;
|
||||
else
|
||||
{
|
||||
// create new and save
|
||||
var newValue = factory();
|
||||
|
||||
Task CacheAsync() => options is null
|
||||
? cache.SetDateTimeAsync(key, newValue, cToken: cToken)
|
||||
: cache.SetDateTimeAsync(key, newValue, options, cToken);
|
||||
|
||||
if (cacheInBackground)
|
||||
_ = Task.Run(async () => await CacheAsync(), cToken);
|
||||
else
|
||||
await CacheAsync();
|
||||
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<DateTime> GetOrSetAsync(this IDistributedCache cache, string key, Func<Task<DateTime>> factory, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken cToken = default)
|
||||
{
|
||||
if (await cache.GetDateTimeAsync(key, cToken) is DateTime dateTimeValue)
|
||||
return dateTimeValue;
|
||||
else
|
||||
{
|
||||
// create new and save
|
||||
var newValue = await factory();
|
||||
|
||||
Task CacheAsync() => options is null
|
||||
? cache.SetDateTimeAsync(key, newValue, cToken: cToken)
|
||||
: cache.SetDateTimeAsync(key, newValue, options, cToken);
|
||||
|
||||
if (cacheInBackground)
|
||||
_ = Task.Run(async () => await CacheAsync(), cToken);
|
||||
else
|
||||
await CacheAsync();
|
||||
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
69
EnvelopeGenerator.Application/Extensions/DIExtensions.cs
Normal file
69
EnvelopeGenerator.Application/Extensions/DIExtensions.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using DigitalData.UserManager.Application.MappingProfiles;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.MappingProfiles;
|
||||
using EnvelopeGenerator.Application.Configurations;
|
||||
using EnvelopeGenerator.Application.Services;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using EnvelopeGenerator.Infrastructure.Repositories;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using DigitalData.Core.Client;
|
||||
using QRCoder;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Extensions;
|
||||
|
||||
public static class DIExtensions
|
||||
{
|
||||
public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfiguration config)
|
||||
{
|
||||
//Inject CRUD Service and repositoriesad
|
||||
services.TryAddScoped<IConfigRepository, ConfigRepository>();
|
||||
services.TryAddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
|
||||
services.TryAddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
|
||||
services.TryAddScoped<IConfigRepository, ConfigRepository>();
|
||||
services.TryAddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
|
||||
services.TryAddScoped<IDocumentStatusRepository, DocumentStatusRepository>();
|
||||
services.TryAddScoped<IEmailTemplateRepository, EmailTemplateRepository>();
|
||||
services.TryAddScoped<IEnvelopeRepository, EnvelopeRepository>();
|
||||
services.TryAddScoped<IEnvelopeCertificateRepository, EnvelopeCertificateRepository>();
|
||||
services.TryAddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
|
||||
services.TryAddScoped<IEnvelopeHistoryRepository, EnvelopeHistoryRepository>();
|
||||
services.TryAddScoped<IEnvelopeReceiverRepository, EnvelopeReceiverRepository>();
|
||||
services.TryAddScoped<IEnvelopeTypeRepository, EnvelopeTypeRepository>();
|
||||
services.TryAddScoped<IReceiverRepository, ReceiverRepository>();
|
||||
services.TryAddScoped<IUserReceiverRepository, UserReceiverRepository>();
|
||||
services.TryAddScoped<IEnvelopeReceiverReadOnlyRepository, EnvelopeReceiverReadOnlyRepository>();
|
||||
services.TryAddScoped<IConfigService, ConfigService>();
|
||||
services.TryAddScoped<IDocumentReceiverElementService, DocumentReceiverElementService>();
|
||||
services.TryAddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
|
||||
services.TryAddScoped<IEnvelopeHistoryService, EnvelopeHistoryService>();
|
||||
services.TryAddScoped<IDocumentStatusService, DocumentStatusService>();
|
||||
services.TryAddScoped<IEmailTemplateService, EmailTemplateService>();
|
||||
services.TryAddScoped<IEnvelopeService, EnvelopeService>();
|
||||
services.TryAddScoped<IEnvelopeCertificateService, EnvelopeCertificateService>();
|
||||
services.TryAddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
|
||||
services.TryAddScoped<IEnvelopeReceiverService, EnvelopeReceiverService>();
|
||||
services.TryAddScoped<IEnvelopeTypeService, EnvelopeTypeService>();
|
||||
services.TryAddScoped<IReceiverService, ReceiverService>();
|
||||
services.TryAddScoped<IUserReceiverService, UserReceiverService>();
|
||||
services.TryAddScoped<IEnvelopeReceiverReadOnlyService, EnvelopeReceiverReadOnlyService>();
|
||||
|
||||
//Auto mapping profiles
|
||||
services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly);
|
||||
services.AddAutoMapper(typeof(UserMappingProfile).Assembly);
|
||||
|
||||
services.Configure<DispatcherParams>(config.GetSection(nameof(DispatcherParams)));
|
||||
services.Configure<MailParams>(config.GetSection(nameof(MailParams)));
|
||||
services.Configure<AuthenticatorParams>(config.GetSection(nameof(AuthenticatorParams)));
|
||||
services.Configure<TotpSmsParams>(config.GetSection(nameof(TotpSmsParams)));
|
||||
|
||||
services.AddHttpClientService<GtxMessagingParams>(config.GetSection(nameof(GtxMessagingParams)));
|
||||
services.TryAddSingleton<ISmsSender, GTXSmsSender>();
|
||||
services.TryAddSingleton<IEnvelopeSmsHandler, EnvelopeSmsHandler>();
|
||||
services.TryAddSingleton<IAuthenticator, Authenticator>();
|
||||
services.TryAddSingleton<QRCodeGenerator>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Extensions
|
||||
{
|
||||
public static class MappingExtensions
|
||||
{
|
||||
public static bool Ok(this GtxMessagingResponse gtxMessagingResponse)
|
||||
=> gtxMessagingResponse.TryGetValue("message-status", out var status)
|
||||
&& status?.ToString()?.ToLower() == "ok";
|
||||
|
||||
public static string ToBase64String(this byte[] bytes)
|
||||
=> Convert.ToBase64String(bytes);
|
||||
}
|
||||
}
|
||||
20
EnvelopeGenerator.Application/Key.cs
Normal file
20
EnvelopeGenerator.Application/Key.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace EnvelopeGenerator.Application
|
||||
{
|
||||
public static class Key
|
||||
{
|
||||
public static readonly string InnerServiceError = nameof(InnerServiceError);
|
||||
public static readonly string EnvelopeNotFound = nameof(EnvelopeNotFound);
|
||||
public static readonly string EnvelopeReceiverNotFound = nameof(EnvelopeReceiverNotFound);
|
||||
public static readonly string AccessCodeNull = nameof(AccessCodeNull);
|
||||
public static readonly string WrongAccessCode = nameof(WrongAccessCode);
|
||||
public static readonly string DataIntegrityIssue = nameof(DataIntegrityIssue);
|
||||
public static readonly string SecurityBreachOrDataIntegrity = nameof(SecurityBreachOrDataIntegrity);
|
||||
public static readonly string PossibleDataIntegrityIssue = nameof(PossibleDataIntegrityIssue);
|
||||
public static readonly string SecurityBreach = nameof(SecurityBreach);
|
||||
public static readonly string PossibleSecurityBreach = nameof(PossibleSecurityBreach);
|
||||
public static readonly string WrongEnvelopeReceiverId = nameof(WrongEnvelopeReceiverId);
|
||||
public static readonly string EnvelopeOrReceiverNonexists = nameof(EnvelopeOrReceiverNonexists);
|
||||
public static readonly string PhoneNumberNonexists = nameof(PhoneNumberNonexists);
|
||||
public static readonly string Default = nameof(Default);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using EnvelopeGenerator.Application.Extensions;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.MappingProfiles
|
||||
{
|
||||
public class BasicDtoMappingProfile : Profile
|
||||
{
|
||||
public BasicDtoMappingProfile()
|
||||
{
|
||||
// Entity to DTO mappings
|
||||
CreateMap<Config, ConfigDto>();
|
||||
CreateMap<DocumentReceiverElement, DocumentReceiverElementDto>();
|
||||
CreateMap<DocumentStatus, DocumentStatusDto>();
|
||||
CreateMap<EmailTemplate, EmailTemplateDto>();
|
||||
CreateMap<Envelope, EnvelopeDto>();
|
||||
CreateMap<EnvelopeCertificate, EnvelopeCertificateDto>();
|
||||
CreateMap<EnvelopeDocument, EnvelopeDocumentDto>();
|
||||
CreateMap<EnvelopeHistory, EnvelopeHistoryDto>();
|
||||
CreateMap<EnvelopeHistory, EnvelopeHistoryCreateDto>();
|
||||
CreateMap<EnvelopeReceiver, EnvelopeReceiverDto>();
|
||||
CreateMap<EnvelopeReceiver, EnvelopeReceiverSecretDto>();
|
||||
CreateMap<EnvelopeType, EnvelopeTypeDto>();
|
||||
CreateMap<Receiver, ReceiverReadDto>();
|
||||
CreateMap<Receiver, ReceiverCreateDto>();
|
||||
CreateMap<Receiver, ReceiverUpdateDto>();
|
||||
CreateMap<UserReceiver, UserReceiverDto>();
|
||||
CreateMap<EnvelopeReceiverReadOnly, EnvelopeReceiverReadOnlyDto>();
|
||||
|
||||
// DTO to Entity mappings
|
||||
CreateMap<ConfigDto, Config>();
|
||||
CreateMap<DocumentReceiverElementDto, DocumentReceiverElement>();
|
||||
CreateMap<DocumentStatusDto, DocumentStatus>();
|
||||
CreateMap<EmailTemplateDto, EmailTemplate>();
|
||||
CreateMap<EnvelopeDto, Envelope>();
|
||||
CreateMap<EnvelopeCertificateDto, EnvelopeCertificate>();
|
||||
CreateMap<EnvelopeDocumentDto, EnvelopeDocument>();
|
||||
CreateMap<EnvelopeHistoryDto, EnvelopeHistory>();
|
||||
CreateMap<EnvelopeHistoryCreateDto, EnvelopeHistory>();
|
||||
CreateMap<EnvelopeReceiverDto, EnvelopeReceiver>();
|
||||
CreateMap<EnvelopeTypeDto, EnvelopeType>();
|
||||
CreateMap<ReceiverReadDto, Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
|
||||
CreateMap<ReceiverCreateDto, Receiver>();
|
||||
CreateMap<ReceiverUpdateDto, Receiver>();
|
||||
CreateMap<UserReceiverDto, UserReceiver>();
|
||||
CreateMap<EnvelopeReceiverBase, EnvelopeReceiverBasicDto>();
|
||||
CreateMap<EnvelopeReceiverReadOnlyCreateDto, EnvelopeReceiverReadOnly>();
|
||||
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, EnvelopeReceiverReadOnly>();
|
||||
|
||||
// Messaging mappings
|
||||
// for GTX messaging
|
||||
CreateMap<GtxMessagingResponse, SmsResponse>()
|
||||
.ConstructUsing(gtxRes => gtxRes.Ok()
|
||||
? new SmsResponse() { Ok = true }
|
||||
: new SmsResponse() { Ok = false, Errors = gtxRes });
|
||||
}
|
||||
}
|
||||
}
|
||||
9
EnvelopeGenerator.Application/Resources/Resource.cs
Normal file
9
EnvelopeGenerator.Application/Resources/Resource.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace EnvelopeGenerator.Application.Resources
|
||||
{
|
||||
/// <summary>
|
||||
/// The place holder class for Resource.*.resx
|
||||
/// </summary>
|
||||
public class Resource
|
||||
{
|
||||
}
|
||||
}
|
||||
261
EnvelopeGenerator.Application/Resources/Resource.de-DE.resx
Normal file
261
EnvelopeGenerator.Application/Resources/Resource.de-DE.resx
Normal file
@@ -0,0 +1,261 @@
|
||||
<?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="and" xml:space="preserve">
|
||||
<value>und</value>
|
||||
</data>
|
||||
<data name="Back" xml:space="preserve">
|
||||
<value>Zurück</value>
|
||||
</data>
|
||||
<data name="Complete" xml:space="preserve">
|
||||
<value>Abschließen</value>
|
||||
</data>
|
||||
<data name="Confirmation" xml:space="preserve">
|
||||
<value>Bestätigung</value>
|
||||
</data>
|
||||
<data name="de-DE" xml:space="preserve">
|
||||
<value>Deutch</value>
|
||||
</data>
|
||||
<data name="DocProtected" xml:space="preserve">
|
||||
<value>Dokument geschützt</value>
|
||||
</data>
|
||||
<data name="DocRejected" xml:space="preserve">
|
||||
<value>Dokument abgelehnt</value>
|
||||
</data>
|
||||
<data name="DocSigned" xml:space="preserve">
|
||||
<value>Dokument unterschrieben</value>
|
||||
</data>
|
||||
<data name="en-US" xml:space="preserve">
|
||||
<value>Englisch</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo1" xml:space="preserve">
|
||||
<value>Sie müssen {0} Vorgang unterzeichen. <span class="highlight highlight-envelope-info-1">Bitte prüfen Sie die Seite {1}</span>.</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo2" xml:space="preserve">
|
||||
<value>Erstellt am {0} von {1}. Sie können den Absender über <span class="highlight highlight-envelope-info-2"><a class="mail-link" href="mailto:{2}?subject={3}&body=Sehr%20geehrter%20{4}%20{5},%0A%0A%0A">{6}</a></span> kontaktieren.</value>
|
||||
</data>
|
||||
<data name="Finalize" xml:space="preserve">
|
||||
<value>Abschließen</value>
|
||||
</data>
|
||||
<data name="Hello" xml:space="preserve">
|
||||
<value>Hallo</value>
|
||||
</data>
|
||||
<data name="HomePageDescription" xml:space="preserve">
|
||||
<value>Das digitale Unterschriftenportal ist eine Plattform, die entwickelt wurde, um Ihre Dokumente sicher zu unterschreiben und zu verwalten. Mit seiner benutzerfreundlichen Oberfläche können Sie Ihre Dokumente schnell hochladen, die Unterschriftsprozesse verfolgen und Ihre digitalen Unterschriftenanwendungen einfach durchführen. Dieses Portal beschleunigt Ihren Arbeitsablauf mit rechtlich gültigen Unterschriften und erhöht gleichzeitig die Sicherheit Ihrer Dokumente.</value>
|
||||
</data>
|
||||
<data name="LocationWarning" xml:space="preserve">
|
||||
<value>Bitte überprüfen Sie die Standortinformationen. Wenn sie falsch sind, korrigieren Sie diese bitte.</value>
|
||||
</data>
|
||||
<data name="LockedBodyAccess" xml:space="preserve">
|
||||
<value>Wir senden Ihnen nun einen Zugriffscode an Ihre hinterlegte Email-Adresse. Dies kann evtl. einige Minuten dauern!</value>
|
||||
</data>
|
||||
<data name="LockedBodyAuthenticator" xml:space="preserve">
|
||||
<value>Bitte geben Sie den in Ihrer Authenticator-App angegebenen TOTP-Code ein.</value>
|
||||
</data>
|
||||
<data name="LockedBodyAuthenticatorNew" xml:space="preserve">
|
||||
<value>Wir haben den QR-Code an Ihre E-Mail-Adresse gesendet. Ihr QR-Code ist bis {0} gültig. Sie können ihn für alle Umschläge verwenden, die Sie an diese E-Mail-Adresse erhalten.</value>
|
||||
</data>
|
||||
<data name="LockedBodySms" xml:space="preserve">
|
||||
<value>Wir haben soeben den Zugangscode als SMS an die von Ihnen angegebene Telefonnummer gesendet.</value>
|
||||
</data>
|
||||
<data name="LockedCodeLabelAccess" xml:space="preserve">
|
||||
<value>Zugriffscode</value>
|
||||
</data>
|
||||
<data name="LockedCodeLabelAuthenticator" xml:space="preserve">
|
||||
<value>TOTP</value>
|
||||
</data>
|
||||
<data name="LockedCodeLabelSms" xml:space="preserve">
|
||||
<value>SMS-Code</value>
|
||||
</data>
|
||||
<data name="LockedFooterBodyAccess" xml:space="preserve">
|
||||
<value>Bitte überprüfen Sie Ihr Email Postfach inklusive Spam-Ordner. Sie können auch den Absender <a class="mail-link" href="mailto:{0}?subject={1}&body={2}" target="_blank">{0}</a> bitten, Ihnen den Code auf anderem Wege zukommen zu lassen.</value>
|
||||
</data>
|
||||
<data name="LockedFooterBodyAuthenticator" xml:space="preserve">
|
||||
<value>Der neue QR-Code wird nur einmal für einen bestimmten Zeitraum gesendet und nach dem Scannen in Ihrer Authenticator-App gespeichert. Er kann für alle Umschläge verwendet werden, die an dieselbe E-Mail-Adresse gesendet werden, bis er abläuft. Wenn Sie die QR-Code-Mail nicht erhalten oder sie sowohl aus der Mail als auch aus authenticator löschen, kontaktieren Sie bitte den Absender.</value>
|
||||
</data>
|
||||
<data name="LockedFooterBodySms" xml:space="preserve">
|
||||
<value>Sie können den Absender bitten, Ihre Rufnummer zu überprüfen. Die Telefonnummer muss mit der Ortsvorwahl eingegeben werden. Andernfalls können Sie beantragen, den Zwei-Faktor-Schutz zu entfernen.</value>
|
||||
</data>
|
||||
<data name="LockedFooterTitleAccess" xml:space="preserve">
|
||||
<value>Sie haben keinen Zugriffscode erhalten?</value>
|
||||
</data>
|
||||
<data name="LockedFooterTitleAuthenticator" xml:space="preserve">
|
||||
<value>Sie haben keinen QR-Code erhalten?</value>
|
||||
</data>
|
||||
<data name="LockedFooterTitleSms" xml:space="preserve">
|
||||
<value>Sie haben keine SMS erhalten?</value>
|
||||
</data>
|
||||
<data name="LockedTitleAccess" xml:space="preserve">
|
||||
<value>Dokument erfordert einen Zugriffscode</value>
|
||||
</data>
|
||||
<data name="LockedTitleAuthenticator" xml:space="preserve">
|
||||
<value>2-Faktor-Authentifizierung</value>
|
||||
</data>
|
||||
<data name="LockedTitleSms" xml:space="preserve">
|
||||
<value>2-Faktor-Authentifizierung</value>
|
||||
</data>
|
||||
<data name="Privacy" xml:space="preserve">
|
||||
<value>Datenschutz</value>
|
||||
</data>
|
||||
<data name="ReadOnlyMessage" xml:space="preserve">
|
||||
<value>Weitergeleitet von {0}. Gültig bis {1}.</value>
|
||||
</data>
|
||||
<data name="Reject" xml:space="preserve">
|
||||
<value>Ablehnen</value>
|
||||
</data>
|
||||
<data name="Rejection" xml:space="preserve">
|
||||
<value>Ablehnung</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1" xml:space="preserve">
|
||||
<value>Dieser Unterzeichnungsvorgang wurde abgelehnt!</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1_ext" xml:space="preserve">
|
||||
<value>Vorgang abgebrochen!</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2" xml:space="preserve">
|
||||
<value>Sie können bei Bedarf mit {0}, <a href="mailto:{1}?subject={2}&body=Sehr geehrte(r)%20{0},%0A%0A%0A">{1}</a> Kontakt aufnehmen.</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2_ext" xml:space="preserve">
|
||||
<value>Das Vorgang wurde von einer der beteiligten Parteien abgelehnt. Sie können bei Bedarf mit {0}, <a href="mailto:{1}?subject={2}&body=Sehr geehrte(r)%20{0},%0A%0A%0A">{1}</a> Kontakt aufnehmen.</value>
|
||||
</data>
|
||||
<data name="RejectionReasonQ" xml:space="preserve">
|
||||
<value>Bitte geben Sie einen Grund an:</value>
|
||||
</data>
|
||||
<data name="SigAgree" xml:space="preserve">
|
||||
<value>Durch Klick auf Abschließen stimme ich zu, dass die abgebildete und übermittelte Signatur als elektronische Darstellung meiner Signatur in den Fällen gelten, in denen ich sie auf Dokumenten, einschließlich rechtsgültiger Verträge verwende.</value>
|
||||
</data>
|
||||
<data name="SignDoc" xml:space="preserve">
|
||||
<value>Dokument unterschreiben</value>
|
||||
</data>
|
||||
<data name="SigningProcessTitle" xml:space="preserve">
|
||||
<value>Titel des Unterzeichnungs-Vorgangs</value>
|
||||
</data>
|
||||
<data name="UnexpectedError" xml:space="preserve">
|
||||
<value>Ein unerwarteter Fehler ist aufgetreten.</value>
|
||||
</data>
|
||||
<data name="ViewDoc" xml:space="preserve">
|
||||
<value>Dokument ansehen</value>
|
||||
</data>
|
||||
<data name="WelcomeToTheESignPortal" xml:space="preserve">
|
||||
<value>Herzlich willkommen im eSign-Portal</value>
|
||||
</data>
|
||||
<data name="WrongAccessCode" xml:space="preserve">
|
||||
<value>Ungültiger Zugangscode.</value>
|
||||
</data>
|
||||
</root>
|
||||
261
EnvelopeGenerator.Application/Resources/Resource.en-US.resx
Normal file
261
EnvelopeGenerator.Application/Resources/Resource.en-US.resx
Normal file
@@ -0,0 +1,261 @@
|
||||
<?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="and" xml:space="preserve">
|
||||
<value>and</value>
|
||||
</data>
|
||||
<data name="Back" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="Complete" xml:space="preserve">
|
||||
<value>Complete</value>
|
||||
</data>
|
||||
<data name="Confirmation" xml:space="preserve">
|
||||
<value>Confirmation</value>
|
||||
</data>
|
||||
<data name="de-DE" xml:space="preserve">
|
||||
<value>German</value>
|
||||
</data>
|
||||
<data name="DocProtected" xml:space="preserve">
|
||||
<value>Document protected</value>
|
||||
</data>
|
||||
<data name="DocRejected" xml:space="preserve">
|
||||
<value>Document rejected</value>
|
||||
</data>
|
||||
<data name="DocSigned" xml:space="preserve">
|
||||
<value>Document signed</value>
|
||||
</data>
|
||||
<data name="en-US" xml:space="preserve">
|
||||
<value>English</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo1" xml:space="preserve">
|
||||
<value>You have to sign {0} process. <span class="highlight highlight-envelope-info-1">Please check page {1}</span>.</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo2" xml:space="preserve">
|
||||
<value>Created on {0} by {1}. You can contact the sender via <span class="highlight highlight-envelope-info-2"><a class="mail-link" href="mailto:{2}?subject={3}&body=Dear%20{4}%20{5},%0A%0A%0A">{6}</a></span>.</value>
|
||||
</data>
|
||||
<data name="Finalize" xml:space="preserve">
|
||||
<value>Finalize</value>
|
||||
</data>
|
||||
<data name="Hello" xml:space="preserve">
|
||||
<value>Hello</value>
|
||||
</data>
|
||||
<data name="HomePageDescription" xml:space="preserve">
|
||||
<value>The Digital Signature Portal is a platform developed for securely signing and managing your documents. With its user-friendly interface, you can quickly upload your documents, track the signing processes, and easily carry out your digital signature applications. This portal accelerates your workflow with legally valid signatures while enhancing the security of your documents.</value>
|
||||
</data>
|
||||
<data name="LocationWarning" xml:space="preserve">
|
||||
<value>Please review the location information. If it is incorrect, kindly make the necessary corrections.</value>
|
||||
</data>
|
||||
<data name="LockedBodyAccess" xml:space="preserve">
|
||||
<value>We will now send you an access code to your registered e-mail address. This may take a few minutes!</value>
|
||||
</data>
|
||||
<data name="LockedBodyAuthenticator" xml:space="preserve">
|
||||
<value>Please enter the TOTP provided in your Authenticator app.</value>
|
||||
</data>
|
||||
<data name="LockedBodyAuthenticatorNew" xml:space="preserve">
|
||||
<value>We have sent the QR code to your e-mail address. Your QR code is valid until {0}. You can use it for all envelopes received at this email address.</value>
|
||||
</data>
|
||||
<data name="LockedBodySms" xml:space="preserve">
|
||||
<value>We have just sent the access code as an SMS to the phone number you provided.</value>
|
||||
</data>
|
||||
<data name="LockedCodeLabelAccess" xml:space="preserve">
|
||||
<value>Access Code</value>
|
||||
</data>
|
||||
<data name="LockedCodeLabelAuthenticator" xml:space="preserve">
|
||||
<value>TOTP</value>
|
||||
</data>
|
||||
<data name="LockedCodeLabelSms" xml:space="preserve">
|
||||
<value>SMS Code</value>
|
||||
</data>
|
||||
<data name="LockedFooterBodyAccess" xml:space="preserve">
|
||||
<value>Please check your email inbox including the spam folder. You can also ask the sender <a class="mail-link" href="mailto:{0}?subject={1}&body={2}" target="_blank">{0}</a> to send you the code by other means.</value>
|
||||
</data>
|
||||
<data name="LockedFooterBodyAuthenticator" xml:space="preserve">
|
||||
<value>The new QR code is sent only once for a given period and is saved in your authenticator app once scanned. It can be used for all envelopes received at the same email address until it expires. If you do not receive the QR code mail or delete it both from the mail and from authenticator, please contact the sender.</value>
|
||||
</data>
|
||||
<data name="LockedFooterBodySms" xml:space="preserve">
|
||||
<value>You can ask the sender to check your phone number. The phone number must be entered with the area code. Otherwise you can request to remove the two-factor protection.</value>
|
||||
</data>
|
||||
<data name="LockedFooterTitleAccess" xml:space="preserve">
|
||||
<value>You have not received an access code?</value>
|
||||
</data>
|
||||
<data name="LockedFooterTitleAuthenticator" xml:space="preserve">
|
||||
<value>You have not received a QR code?</value>
|
||||
</data>
|
||||
<data name="LockedFooterTitleSms" xml:space="preserve">
|
||||
<value>You have not received an SMS?</value>
|
||||
</data>
|
||||
<data name="LockedTitleAccess" xml:space="preserve">
|
||||
<value>Document requires an access code</value>
|
||||
</data>
|
||||
<data name="LockedTitleAuthenticator" xml:space="preserve">
|
||||
<value>2-Factor Authentication</value>
|
||||
</data>
|
||||
<data name="LockedTitleSms" xml:space="preserve">
|
||||
<value>2-Factor Authentication</value>
|
||||
</data>
|
||||
<data name="Privacy" xml:space="preserve">
|
||||
<value>Privacy</value>
|
||||
</data>
|
||||
<data name="ReadOnlyMessage" xml:space="preserve">
|
||||
<value>Forwarded by {0}. Valid until {1}.</value>
|
||||
</data>
|
||||
<data name="Reject" xml:space="preserve">
|
||||
<value>Reject</value>
|
||||
</data>
|
||||
<data name="Rejection" xml:space="preserve">
|
||||
<value>Rejection</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1" xml:space="preserve">
|
||||
<value>This signing process was rejected!</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1_ext" xml:space="preserve">
|
||||
<value>Process canceled!</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2" xml:space="preserve">
|
||||
<value>You can contact {0}, <a href="mailto:{1}?subject={2}&body=Dear%20{0},%0A%0A%0A">{1}</a> if required.</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2_ext" xml:space="preserve">
|
||||
<value>The process has been rejected by one of the parties involved. You can contact {0}, <a href="mailto:{1}?subject={2}&body=Dear%20{0},%0A%0A%0A">{1}</a> if required.</value>
|
||||
</data>
|
||||
<data name="RejectionReasonQ" xml:space="preserve">
|
||||
<value>Please give a reason:</value>
|
||||
</data>
|
||||
<data name="SigAgree" xml:space="preserve">
|
||||
<value>By clicking on Finalize, I agree that the signature shown and submitted is an electronic representation of my signature in cases where I use it on documents, including legally binding contracts.</value>
|
||||
</data>
|
||||
<data name="SignDoc" xml:space="preserve">
|
||||
<value>Sign document</value>
|
||||
</data>
|
||||
<data name="SigningProcessTitle" xml:space="preserve">
|
||||
<value>Title of the signing process</value>
|
||||
</data>
|
||||
<data name="UnexpectedError" xml:space="preserve">
|
||||
<value>An unexpected error has occurred.</value>
|
||||
</data>
|
||||
<data name="ViewDoc" xml:space="preserve">
|
||||
<value>View document</value>
|
||||
</data>
|
||||
<data name="WelcomeToTheESignPortal" xml:space="preserve">
|
||||
<value>Welcome to the eSign portal</value>
|
||||
</data>
|
||||
<data name="WrongAccessCode" xml:space="preserve">
|
||||
<value>Invalid access code.</value>
|
||||
</data>
|
||||
</root>
|
||||
71
EnvelopeGenerator.Application/Services/Authenticator.cs
Normal file
71
EnvelopeGenerator.Application/Services/Authenticator.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using EnvelopeGenerator.Application.Configurations;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using Microsoft.Extensions.Options;
|
||||
using OtpNet;
|
||||
using QRCoder;
|
||||
using System.Text;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class Authenticator : IAuthenticator
|
||||
{
|
||||
public static Lazy<Authenticator> LazyStatic => new(() => new Authenticator(Options.Create<AuthenticatorParams>(new()), new QRCodeGenerator()));
|
||||
|
||||
public static Authenticator Static => LazyStatic.Value;
|
||||
|
||||
private readonly AuthenticatorParams _params;
|
||||
|
||||
private readonly QRCodeGenerator _qrCodeGenerator;
|
||||
|
||||
public Authenticator(IOptions<AuthenticatorParams> options, QRCodeGenerator qrCodeGenerator)
|
||||
{
|
||||
_params = options.Value;
|
||||
_qrCodeGenerator = qrCodeGenerator;
|
||||
}
|
||||
|
||||
public string GenerateCode(int length)
|
||||
{
|
||||
//TODO: Inject Random as a singleton to support multithreading to improve performance.
|
||||
Random random = new();
|
||||
|
||||
if (length <= 0)
|
||||
throw new ArgumentException("Password length must be greater than 0.");
|
||||
|
||||
var passwordBuilder = new StringBuilder(length);
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
passwordBuilder.Append(_params.CharPool[random.Next(_params.CharPool.Length)]);
|
||||
|
||||
return passwordBuilder.ToString();
|
||||
}
|
||||
|
||||
public string GenerateTotpSecretKey(int? length = null)
|
||||
=> Base32Encoding.ToString(KeyGeneration.GenerateRandomKey(length ?? _params.DefaultTotpSecretKeyLength));
|
||||
|
||||
public byte[] GenerateTotpQrCode(string userEmail, string secretKey, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null)
|
||||
{
|
||||
var url = string.Format(totpUrlFormat ?? _params.TotpUrlFormat,
|
||||
Uri.EscapeDataString(userEmail),
|
||||
Uri.EscapeDataString(secretKey),
|
||||
Uri.EscapeDataString(issuer ?? _params.TotpIssuer));
|
||||
using var qrCodeData = _qrCodeGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
|
||||
using var qrCode = new BitmapByteQRCode(qrCodeData);
|
||||
return qrCode.GetGraphic(pixelsPerModule ?? _params.TotpQRPixelsPerModule);
|
||||
}
|
||||
|
||||
public byte[] GenerateTotpQrCode(string userEmail, int? length = null, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null)
|
||||
{
|
||||
return GenerateTotpQrCode(
|
||||
userEmail: userEmail,
|
||||
secretKey: GenerateTotpSecretKey(length: length),
|
||||
issuer: issuer,
|
||||
totpUrlFormat: totpUrlFormat,
|
||||
pixelsPerModule: pixelsPerModule);
|
||||
}
|
||||
|
||||
public string GenerateTotp(string secretKey, int step = 30) => new Totp(Base32Encoding.ToBytes(secretKey), step).ComputeTotp();
|
||||
|
||||
public bool VerifyTotp(string totpCode, string secretKey, int step = 30, VerificationWindow? window = null)
|
||||
=> new Totp(Base32Encoding.ToBytes(secretKey), step).VerifyTotp(totpCode, out _, window);
|
||||
}
|
||||
}
|
||||
60
EnvelopeGenerator.Application/Services/ConfigService.cs
Normal file
60
EnvelopeGenerator.Application/Services/ConfigService.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class ConfigService : ReadService<IConfigRepository, ConfigDto, Config, int>, IConfigService
|
||||
{
|
||||
private static readonly Guid DefaultConfigCacheId = Guid.NewGuid();
|
||||
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly ILogger<ConfigService> _logger;
|
||||
public ConfigService(IConfigRepository repository, IMapper mapper, IMemoryCache memoryCache, ILogger<ConfigService> logger) : base(repository, mapper)
|
||||
{
|
||||
_cache = memoryCache;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<DataResult<ConfigDto>> ReadFirstAsync()
|
||||
{
|
||||
var config = await _repository.ReadFirstAsync();
|
||||
return config is null
|
||||
? Result.Fail<ConfigDto>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, "There is no configuration in DB.")
|
||||
: Result.Success(_mapper.Map<ConfigDto>(config));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the default configuration asynchronously.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The configuration is cached in memory upon the first retrieval. If the configuration is updated,
|
||||
/// the application needs to be restarted for the changes to take effect as the memory cache will not be updated automatically.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous read operation. The task result contains the default configuration as a <see cref="ConfigDto"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown when the default configuration cannot be found.
|
||||
/// </exception>
|
||||
public async Task<ConfigDto> ReadDefaultAsync()
|
||||
{
|
||||
var config = await _cache.GetOrCreateAsync(DefaultConfigCacheId, _ => ReadFirstAsync().ThenAsync(
|
||||
Success: config => config,
|
||||
Fail: (mssg, ntc) =>
|
||||
{
|
||||
_logger.LogNotice(ntc);
|
||||
throw new InvalidOperationException("Default configuration cannot find.");
|
||||
}));
|
||||
|
||||
return config!;
|
||||
}
|
||||
|
||||
public async Task<string> ReadDefaultSignatureHost() => (await ReadDefaultAsync()).SignatureHost;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class DocumentReceiverElementService : BasicCRUDService<IDocumentReceiverElementRepository, DocumentReceiverElementDto, DocumentReceiverElement, int>, IDocumentReceiverElementService
|
||||
{
|
||||
public DocumentReceiverElementService(IDocumentReceiverElementRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class DocumentStatusService : BasicCRUDService<IDocumentStatusRepository, DocumentStatusDto, DocumentStatus, int>, IDocumentStatusService
|
||||
{
|
||||
public DocumentStatusService(IDocumentStatusRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
using DigitalData.Core.DTO;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EmailTemplateService : BasicCRUDService<IEmailTemplateRepository, EmailTemplateDto, EmailTemplate, int>, IEmailTemplateService
|
||||
{
|
||||
public EmailTemplateService(IEmailTemplateRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<DataResult<EmailTemplateDto>> ReadByNameAsync(EmailTemplateType type)
|
||||
{
|
||||
var temp = await _repository.ReadByNameAsync(type);
|
||||
return temp is null
|
||||
? Result.Fail<EmailTemplateDto>()
|
||||
.Message(Key.InnerServiceError)
|
||||
.Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"EmailTemplateType '{type}' is not found in DB. Please, define required e-mail template.")
|
||||
: Result.Success(_mapper.Map<EmailTemplateDto>(temp));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeCertificateService : BasicCRUDService<IEnvelopeCertificateRepository, EnvelopeCertificateDto, EnvelopeCertificate, int>, IEnvelopeCertificateService
|
||||
{
|
||||
public EnvelopeCertificateService(IEnvelopeCertificateRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeDocumentService : BasicCRUDService<IEnvelopeDocumentRepository, EnvelopeDocumentDto, EnvelopeDocument, int>, IEnvelopeDocumentService
|
||||
{
|
||||
public EnvelopeDocumentService(IEnvelopeDocumentRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeHistoryService : CRUDService<IEnvelopeHistoryRepository, EnvelopeHistoryCreateDto, EnvelopeHistoryDto, EnvelopeHistoryDto, EnvelopeHistory, long>, IEnvelopeHistoryService
|
||||
{
|
||||
public EnvelopeHistoryService(IEnvelopeHistoryRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<int> CountAsync(int? envelopeId = null, string? userReference = null, int? status = null) => await _repository.CountAsync(envelopeId: envelopeId, userReference: userReference, status: status);
|
||||
|
||||
public async Task<bool> HasStatus(EnvelopeStatus status, int envelopeId, string userReference) => await _repository.CountAsync(
|
||||
envelopeId: envelopeId,
|
||||
userReference: userReference,
|
||||
status: (int) status) > 0;
|
||||
|
||||
public async Task<bool> AccessCodeAlreadyRequested(int envelopeId, string userReference) => await _repository.CountAsync(
|
||||
envelopeId: envelopeId,
|
||||
userReference:userReference,
|
||||
status: (int) EnvelopeStatus.AccessCodeRequested) > 0;
|
||||
|
||||
public async Task<bool> IsSigned(int envelopeId, string userReference) => await _repository.CountAsync(
|
||||
envelopeId: envelopeId,
|
||||
userReference: userReference,
|
||||
status: (int) EnvelopeStatus.DocumentSigned) > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified envelope has been rejected.
|
||||
/// <para><b>Note:</b> <i>If any document within the envelope is rejected, the entire envelope will be considered rejected.</i></para>
|
||||
/// </summary>
|
||||
/// <param name="envelopeId">The ID of the envelope to check.</param>
|
||||
/// <param name="userReference">Optional user reference associated with the envelope.</param>
|
||||
/// <returns>A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the envelope is rejected.</returns>
|
||||
public async Task<bool> IsRejected(int envelopeId, string? userReference = null)
|
||||
{
|
||||
return await _repository.CountAsync(
|
||||
envelopeId: envelopeId,
|
||||
userReference: userReference,
|
||||
status: (int)EnvelopeStatus.DocumentRejected) > 0;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null, bool withSender = false, bool withReceiver = false)
|
||||
{
|
||||
var histDTOs = _mapper.Map<IEnumerable<EnvelopeHistoryDto>>(
|
||||
await _repository.ReadAsync(
|
||||
envelopeId: envelopeId,
|
||||
userReference: userReference,
|
||||
status: status,
|
||||
withSender: withSender,
|
||||
withReceiver: withReceiver));
|
||||
return referenceType is null ? histDTOs : histDTOs.Where(h => h.ReferenceType == referenceType);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null) =>
|
||||
await ReadAsync(envelopeId: envelopeId, userReference: userReference, status: (int)EnvelopeStatus.DocumentRejected, withReceiver:true);
|
||||
|
||||
//TODO: use IQueryable in repository to incerease the performance
|
||||
public async Task<IEnumerable<ReceiverReadDto>> ReadRejectingReceivers(int envelopeId)
|
||||
{
|
||||
var envelopes = await ReadRejectedAsync(envelopeId);
|
||||
return envelopes is null
|
||||
? Enumerable.Empty<ReceiverReadDto>()
|
||||
: envelopes
|
||||
.Where(eh => eh?.Receiver != null)
|
||||
.Select(eh => eh.Receiver!);
|
||||
}
|
||||
|
||||
public async Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null) =>
|
||||
await CreateAsync(new (EnvelopeId: envelopeId, UserReference: userReference, Status: (int)status, ActionDate: DateTime.Now, Comment: comment))
|
||||
.ThenAsync(
|
||||
Success: id => Result.Success(id),
|
||||
Fail: (mssg, ntc) => Result.Fail<long>().Message(mssg).Notice(ntc)
|
||||
);
|
||||
}
|
||||
}
|
||||
175
EnvelopeGenerator.Application/Services/EnvelopeMailService.cs
Normal file
175
EnvelopeGenerator.Application/Services/EnvelopeMailService.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.DTOs.EmailOut;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Services;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Common;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
using EnvelopeGenerator.Extensions;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Application.Configurations;
|
||||
using EnvelopeGenerator.Application.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeMailService : EmailOutService, IEnvelopeMailService
|
||||
{
|
||||
private readonly IEmailTemplateService _tempService;
|
||||
private readonly IEnvelopeReceiverService _envRcvService;
|
||||
private readonly DispatcherParams _dConfig;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Dictionary<string, string> _placeholders;
|
||||
private readonly IAuthenticator _authenticator;
|
||||
|
||||
public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherParams> dispatcherConfigOptions, IConfigService configService, IOptions<MailParams> mailConfig, IAuthenticator authenticator) : base(repository, mapper)
|
||||
{
|
||||
_tempService = tempService;
|
||||
_envRcvService = envelopeReceiverService;
|
||||
_dConfig = dispatcherConfigOptions.Value;
|
||||
_configService = configService;
|
||||
_placeholders = mailConfig.Value.Placeholders;
|
||||
_authenticator = authenticator;
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null)
|
||||
{
|
||||
if (accessCode is not null)
|
||||
_placeholders["[DOCUMENT_ACCESS_CODE]"] = accessCode;
|
||||
|
||||
if(envelopeReceiverDto?.Envelope is not null && envelopeReceiverDto.Receiver is not null)
|
||||
{
|
||||
var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).EncodeEnvelopeReceiverId();
|
||||
var sigHost = await _configService.ReadDefaultSignatureHost();
|
||||
var linkToDoc = $"{sigHost}/EnvelopeKey/{erId}";
|
||||
_placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
|
||||
_placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)] + "..";
|
||||
}
|
||||
|
||||
return _placeholders;
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, string>> CreatePlaceholders(EnvelopeReceiverReadOnlyDto? readOnlyDto = null)
|
||||
{
|
||||
if (readOnlyDto?.Envelope is not null && readOnlyDto.Receiver is not null)
|
||||
{
|
||||
_placeholders["[NAME_RECEIVER]"] = await _envRcvService.ReadLastUsedReceiverNameByMail(readOnlyDto.AddedWho).ThenAsync(res => res, (msg, ntc) => string.Empty) ?? string.Empty;
|
||||
var erReadOnlyId = (readOnlyDto.Id).EncodeEnvelopeReceiverId();
|
||||
var sigHost = await _configService.ReadDefaultSignatureHost();
|
||||
var linkToDoc = $"{sigHost}/EnvelopeKey/{erReadOnlyId}";
|
||||
_placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
|
||||
_placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)] + "..";
|
||||
}
|
||||
|
||||
return _placeholders;
|
||||
}
|
||||
|
||||
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverDto dto, EmailTemplateType tempType, Dictionary<string, object>? optionalPlaceholders = null)
|
||||
{
|
||||
var tempSerResult = await _tempService.ReadByNameAsync(tempType);
|
||||
if (tempSerResult.IsFailed)
|
||||
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"The email cannot send because '{tempType}' template cannot found.");
|
||||
var temp = tempSerResult.Data;
|
||||
|
||||
var mail = new EmailOutCreateDto()
|
||||
{
|
||||
EmailAddress = dto.Receiver!.EmailAddress,
|
||||
EmailSubj = temp.Subject,
|
||||
EmailBody = temp.Body,
|
||||
//email_type = envelope_status,
|
||||
//message = envelope_message,
|
||||
ReferenceId = dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
|
||||
ReferenceString = dto!.Envelope!.Uuid, //REFERENCE_STRING = ENVELOPE_UUID
|
||||
//receiver_name = receiver.name,
|
||||
//receiver_access_code = receiver.access_code,
|
||||
//sender_adress = envelope.user.email,
|
||||
//sender_name = envelope.user.full_name,
|
||||
//envelope_title = envelope.title,
|
||||
ReminderTypeId = _dConfig.ReminderTypeId,
|
||||
SendingProfile = _dConfig.SendingProfile,
|
||||
EntityId = null,
|
||||
WfId = (int) EnvelopeStatus.MessageAccessCodeSent,
|
||||
WfReference = null,
|
||||
AddedWho = _dConfig.AddedWho,
|
||||
EmailAttmt1 = _dConfig.EmailAttmt1
|
||||
};
|
||||
|
||||
//get acccess code
|
||||
var acResult = await _envRcvService.ReadAccessCodeByIdAsync(envelopeId: dto.EnvelopeId, receiverId: dto.ReceiverId);
|
||||
if (acResult.IsFailed)
|
||||
return acResult.ToFail<int>().Notice(LogLevel.Error, "Therefore, access code cannot be sent");
|
||||
var accessCode = acResult.Data;
|
||||
|
||||
var placeholders = await CreatePlaceholders(accessCode: accessCode, envelopeReceiverDto: dto);
|
||||
|
||||
// Add optional place holders.
|
||||
if (optionalPlaceholders is not null)
|
||||
foreach (var oph in optionalPlaceholders)
|
||||
placeholders[oph.Key] = oph.Value.ToString() ?? "NULL";
|
||||
|
||||
//TODO: remove the requirement to add the models using reflections
|
||||
return await CreateWithTemplateAsync(createDto: mail,placeholders: placeholders,
|
||||
dto, dto.Envelope.User!, dto.Envelope);
|
||||
}
|
||||
|
||||
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto, Dictionary<string, object>? optionalPlaceholders = null)
|
||||
{
|
||||
var tempSerResult = await _tempService.ReadByNameAsync(EmailTemplateType.DocumentShared);
|
||||
if (tempSerResult.IsFailed)
|
||||
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"The email cannot send because '{Constants.EmailTemplateType.DocumentShared}' template cannot found.");
|
||||
var temp = tempSerResult.Data;
|
||||
|
||||
var mail = new EmailOutCreateDto()
|
||||
{
|
||||
EmailAddress = dto.ReceiverMail,
|
||||
EmailSubj = temp.Subject,
|
||||
EmailBody = temp.Body,
|
||||
//TODO: remove int casting when all
|
||||
ReferenceId = (int) dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
|
||||
ReferenceString = dto.Envelope!.Uuid, //REFERENCE_STRING = ENVELOPE_UUID
|
||||
//receiver_name = receiver.name,
|
||||
//receiver_access_code = receiver.access_code,
|
||||
//sender_adress = envelope.user.email,
|
||||
//sender_name = envelope.user.full_name,
|
||||
//envelope_title = envelope.title,
|
||||
ReminderTypeId = _dConfig.ReminderTypeId,
|
||||
SendingProfile = _dConfig.SendingProfile,
|
||||
EntityId = null,
|
||||
WfId = (int)EnvelopeStatus.EnvelopeShared,
|
||||
WfReference = null,
|
||||
AddedWho = _dConfig.AddedWho,
|
||||
EmailAttmt1 = _dConfig.EmailAttmt1
|
||||
};
|
||||
|
||||
var placeholders = await CreatePlaceholders(readOnlyDto: dto);
|
||||
|
||||
// Add optional place holders.
|
||||
if (optionalPlaceholders is not null)
|
||||
foreach (var oph in optionalPlaceholders)
|
||||
placeholders[oph.Key] = oph.Value.ToString() ?? "NULL";
|
||||
|
||||
return await CreateWithTemplateAsync(createDto: mail, placeholders: placeholders, dto.Envelope);
|
||||
}
|
||||
|
||||
public async Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto dto) => await SendAsync(dto: dto, tempType: EmailTemplateType.DocumentAccessCodeReceived);
|
||||
|
||||
public Task<DataResult<int>> SendTFAQrCodeAsync(EnvelopeReceiverDto dto)
|
||||
{
|
||||
// Check if receiver or secret key is null
|
||||
if (dto.Receiver is null)
|
||||
throw new ArgumentNullException(nameof(dto), $"TFA Qr Code cannot sent. Receiver information is missing. Envelope receiver dto is {JsonConvert.SerializeObject(dto)}");
|
||||
if (dto.Receiver.TotpSecretkey is null)
|
||||
throw new ArgumentNullException(nameof(dto), $"TFA Qr Code cannot sent. Receiver.TotpSecretKey is null. Envelope receiver dto is {JsonConvert.SerializeObject(dto)}");
|
||||
|
||||
var totp_qr_64 = _authenticator.GenerateTotpQrCode(userEmail: dto.Receiver.EmailAddress, secretKey: dto.Receiver.TotpSecretkey).ToBase64String();
|
||||
return SendAsync(dto, EmailTemplateType.TotpSecret, new()
|
||||
{
|
||||
{"[TFA_QR_CODE]", totp_qr_64 },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeReceiverReadOnlyService : CRUDService<IEnvelopeReceiverReadOnlyRepository, EnvelopeReceiverReadOnlyCreateDto, EnvelopeReceiverReadOnlyDto, EnvelopeReceiverReadOnlyUpdateDto, EnvelopeReceiverReadOnly, long>, IEnvelopeReceiverReadOnlyService
|
||||
{
|
||||
public EnvelopeReceiverReadOnlyService(IEnvelopeReceiverReadOnlyRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using EnvelopeGenerator.Extensions;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeReceiverService : BasicCRUDService<IEnvelopeReceiverRepository, EnvelopeReceiverDto, EnvelopeReceiver, (int Envelope, int Receiver)>, IEnvelopeReceiverService
|
||||
{
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
|
||||
private readonly ISmsSender _smsSender;
|
||||
|
||||
public EnvelopeReceiverService(IEnvelopeReceiverRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper, ISmsSender smsSender)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
_localizer = localizer;
|
||||
_smsSender = smsSender;
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true, bool readOnly = true)
|
||||
{
|
||||
var env_rcvs = await _repository.ReadBySignatureAsync(signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver, readOnly: readOnly);
|
||||
return Result.Success(_mapper.Map<IEnumerable<EnvelopeReceiverDto>>(env_rcvs));
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false, bool readOnly = true)
|
||||
{
|
||||
var env_rcvs = await _repository.ReadByUuidAsync(uuid: uuid, withEnvelope: withEnvelope, withReceiver: withReceiver, readOnly: readOnly);
|
||||
return Result.Success(_mapper.Map<IEnumerable<EnvelopeReceiverDto>>(env_rcvs));
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<string?>>> ReadAccessCodeByUuidAsync(string uuid, bool withEnvelope = false, bool withReceiver = true)
|
||||
{
|
||||
var env_rcvs = await _repository.ReadByUuidAsync(uuid: uuid, withEnvelope: withEnvelope, withReceiver: withReceiver);
|
||||
return Result.Success(env_rcvs.Select(er => er.AccessCode));
|
||||
}
|
||||
|
||||
public async Task<DataResult<EnvelopeReceiverDto>> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true, bool readOnly = true)
|
||||
{
|
||||
var env_rcv = await _repository.ReadByUuidSignatureAsync(uuid: uuid, signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver, readOnly: readOnly);
|
||||
if (env_rcv is null)
|
||||
return Result.Fail<EnvelopeReceiverDto>()
|
||||
.Message(Key.EnvelopeReceiverNotFound);
|
||||
|
||||
return Result.Success(_mapper.Map<EnvelopeReceiverDto>(env_rcv));
|
||||
}
|
||||
|
||||
public async Task<DataResult<EnvelopeReceiverSecretDto>> ReadWithSecretByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true, bool readOnly = true)
|
||||
{
|
||||
var env_rcv = await _repository.ReadByUuidSignatureAsync(uuid: uuid, signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver, readOnly: readOnly);
|
||||
if (env_rcv is null)
|
||||
return Result.Fail<EnvelopeReceiverSecretDto>()
|
||||
.Message(Key.EnvelopeReceiverNotFound);
|
||||
|
||||
return Result.Success(_mapper.Map<EnvelopeReceiverSecretDto>(env_rcv));
|
||||
}
|
||||
|
||||
public async Task<DataResult<EnvelopeReceiverDto>> ReadByEnvelopeReceiverIdAsync(string envelopeReceiverId, bool withEnvelope = true, bool withReceiver = true, bool readOnly = true)
|
||||
{
|
||||
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
|
||||
if (uuid is null || signature is null)
|
||||
return Result.Fail<EnvelopeReceiverDto>()
|
||||
.Message(_localizer[Key.WrongEnvelopeReceiverId])
|
||||
.Notice(LogLevel.Warning, (uuid, signature).ToTitle())
|
||||
.Notice(LogLevel.Warning, EnvelopeFlag.WrongEnvelopeReceiverId)
|
||||
.Notice(LogLevel.Warning, Flag.PossibleSecurityBreach);
|
||||
|
||||
return await ReadByUuidSignatureAsync(uuid: uuid, signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver, readOnly: readOnly);
|
||||
}
|
||||
|
||||
public async Task<DataResult<bool>> VerifyAccessCodeAsync(string uuid, string signature, string accessCode)
|
||||
{
|
||||
var er = await _repository.ReadByUuidSignatureAsync(uuid: uuid, signature: signature);
|
||||
|
||||
if (er is null)
|
||||
return Result.Fail<bool>()
|
||||
.Message(_localizer[Key.EnvelopeOrReceiverNonexists])
|
||||
.Notice(LogLevel.Warning, (uuid, signature).ToTitle())
|
||||
.Notice(LogLevel.Warning, EnvelopeFlag.EnvelopeOrReceiverNonexists)
|
||||
.Notice(LogLevel.Warning, Flag.PossibleDataIntegrityIssue);
|
||||
|
||||
var actualAccessCode = er.AccessCode;
|
||||
|
||||
if (actualAccessCode is null)
|
||||
return Result.Fail<bool>()
|
||||
.Message(_localizer[Key.AccessCodeNull])
|
||||
.Notice(LogLevel.Critical, (uuid, signature).ToTitle())
|
||||
.Notice(LogLevel.Critical, EnvelopeFlag.AccessCodeNull)
|
||||
.Notice(LogLevel.Critical, Flag.DataIntegrityIssue);
|
||||
|
||||
else if (accessCode != actualAccessCode)
|
||||
return Result.Success(false).Message(_localizer[Key.WrongAccessCode]);
|
||||
else
|
||||
return Result.Success(true);
|
||||
}
|
||||
|
||||
public async Task<DataResult<bool>> VerifyAccessCodeAsync(string envelopeReceiverId, string accessCode)
|
||||
{
|
||||
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
|
||||
if (uuid is null || signature is null)
|
||||
return Result.Fail<bool>()
|
||||
.Message(Key.WrongEnvelopeReceiverId)
|
||||
.Notice(LogLevel.Critical, EnvelopeFlag.WrongEnvelopeReceiverId)
|
||||
.Notice(LogLevel.Critical, Flag.SecurityBreach)
|
||||
.Notice(LogLevel.Critical, "Attempt to verify access code detected. Such actions are generally not initiated by well-intentioned users. Potential security breach suspected. Immediate investigation required.");
|
||||
|
||||
return await VerifyAccessCodeAsync(uuid: uuid, signature: signature, accessCode: accessCode);
|
||||
}
|
||||
|
||||
public async Task<DataResult<bool>> IsExisting(string envelopeReceiverId)
|
||||
{
|
||||
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
|
||||
if (uuid is null || signature is null)
|
||||
return Result.Fail<bool>().Notice(LogLevel.Warning, EnvelopeFlag.NonDecodableEnvelopeReceiverId, "In IsExisting(string envelopeReceiverId)");
|
||||
|
||||
int count = await _repository.CountAsync(uuid:uuid, signature:signature);
|
||||
return Result.Success(count > 0);
|
||||
}
|
||||
|
||||
public async Task<DataResult<string>> ReadAccessCodeByIdAsync(int envelopeId, int receiverId)
|
||||
{
|
||||
var code = await _repository.ReadAccessCodeByIdAsync(envelopeId: envelopeId, receiverId: receiverId);
|
||||
return code is null ?
|
||||
Result.Fail<string>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"Access code is null. Envelope ID is {envelopeId} and receiver ID {receiverId}")
|
||||
: Result.Success(code);
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses)
|
||||
{
|
||||
var er_list = await _repository.ReadByUsernameAsync(username: username, min_status: min_status, max_status: max_status, ignore_statuses: ignore_statuses);
|
||||
var dto_list = _mapper.Map<IEnumerable<EnvelopeReceiverDto>>(er_list);
|
||||
return Result.Success(dto_list);
|
||||
}
|
||||
|
||||
public async Task<DataResult<string?>> ReadLastUsedReceiverNameByMail(string mail)
|
||||
{
|
||||
var er = await _repository.ReadLastByReceiver(mail);
|
||||
return er is null ? Result.Fail<string?>().Notice(LogLevel.None, Flag.NotFound) : Result.Success(er.Name);
|
||||
}
|
||||
|
||||
public async Task<DataResult<SmsResponse>> SendSmsAsync(string envelopeReceiverId, string message)
|
||||
{
|
||||
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
|
||||
if (uuid is null || signature is null)
|
||||
return Result.Fail<SmsResponse>()
|
||||
.Message(_localizer[Key.WrongEnvelopeReceiverId])
|
||||
.Notice(LogLevel.Warning, (uuid, signature).ToTitle())
|
||||
.Notice(LogLevel.Warning, EnvelopeFlag.WrongEnvelopeReceiverId)
|
||||
.Notice(LogLevel.Warning, Flag.PossibleSecurityBreach);
|
||||
|
||||
var env_rcv = await _repository.ReadByUuidSignatureAsync(uuid: uuid, signature: signature, withEnvelope: false, withReceiver: false);
|
||||
if (env_rcv is null)
|
||||
return Result.Fail<SmsResponse>()
|
||||
.Message(Key.EnvelopeReceiverNotFound);
|
||||
|
||||
if (env_rcv.PhoneNumber is null)
|
||||
return Result.Fail<SmsResponse>()
|
||||
.Message(Key.PhoneNumberNonexists)
|
||||
.Notice(LogLevel.Error, Flag.NotFound, $"An attempt was made to send sms to the user whose phone number is null. Envelope recipient ID is {envelopeReceiverId}, UUID is {uuid} and signature is {signature}.");
|
||||
|
||||
var res = await _smsSender.SendSmsAsync(recipient: env_rcv.PhoneNumber, message: message);
|
||||
|
||||
return Result.Success(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
EnvelopeGenerator.Application/Services/EnvelopeService.cs
Normal file
43
EnvelopeGenerator.Application/Services/EnvelopeService.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeService : BasicCRUDService<IEnvelopeRepository, EnvelopeDto, Envelope, int>, IEnvelopeService
|
||||
{
|
||||
public EnvelopeService(IEnvelopeRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false)
|
||||
{
|
||||
var envelopes = await _repository.ReadAllWithAsync(documents: documents, history: history, documentReceiverElement: documentReceiverElement);
|
||||
var readDto = _mapper.Map<IEnumerable<EnvelopeDto>>(envelopes);
|
||||
return Result.Success(readDto);
|
||||
}
|
||||
|
||||
public async Task<DataResult<EnvelopeDto>> ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false)
|
||||
{
|
||||
var envelope = await _repository.ReadByUuidAsync(uuid: uuid, withDocuments: withDocuments, withHistory: withHistory, withDocumentReceiverElement: withDocumentReceiverElement, withUser:withUser, withAll:withAll);
|
||||
|
||||
if (envelope is null)
|
||||
return Result.Fail<EnvelopeDto>();
|
||||
|
||||
var readDto = _mapper.Map<EnvelopeDto>(envelope);
|
||||
return Result.Success(readDto);
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<EnvelopeDto>>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses)
|
||||
{
|
||||
var users = await _repository.ReadByUserAsync(userId: userId, min_status: min_status, max_status: max_status, ignore_statuses: ignore_statuses);
|
||||
var readDto = _mapper.Map<IEnumerable<EnvelopeDto>>(users);
|
||||
return Result.Success(readDto);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs
Normal file
54
EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using EnvelopeGenerator.Application.Configurations;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
using EnvelopeGenerator.Application.Extensions;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services;
|
||||
|
||||
public class EnvelopeSmsHandler : IEnvelopeSmsHandler
|
||||
{
|
||||
private readonly ISmsSender _sender;
|
||||
|
||||
private readonly TotpSmsParams _totpSmsParams;
|
||||
|
||||
private readonly IDistributedCache _dCache;
|
||||
|
||||
private readonly IAuthenticator _authenticator;
|
||||
|
||||
public EnvelopeSmsHandler(ISmsSender sender, IOptions<TotpSmsParams> totpSmsParamsOptions, IDistributedCache distributedCache, IAuthenticator authenticator)
|
||||
{
|
||||
_sender = sender;
|
||||
_totpSmsParams = totpSmsParamsOptions.Value;
|
||||
_dCache = distributedCache;
|
||||
_authenticator = authenticator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If expiration is passed then, sends sms and returns smsResponse and up-to-date expiration; otherwise send expiration.
|
||||
/// </summary>
|
||||
/// <param name="er_secret"></param>
|
||||
/// <param name="cToken"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(SmsResponse? SmsResponse, DateTime Expiration)> SendTotpAsync(EnvelopeReceiverSecretDto er_secret, CancellationToken cToken = default)
|
||||
{
|
||||
var key = string.Format(_totpSmsParams.Expiration.CacheKeyFormat, er_secret.EnvelopeId, er_secret.ReceiverId);
|
||||
var expiration = await _dCache.GetDateTimeAsync(key, cToken);
|
||||
|
||||
if(expiration is DateTime expirationDateTime && expirationDateTime >= DateTime.Now)
|
||||
return (null, expirationDateTime);
|
||||
else
|
||||
{
|
||||
var new_expiration = DateTime.Now.AddSeconds(_totpSmsParams.TotpStep);
|
||||
var totp = _authenticator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, _totpSmsParams.TotpStep);
|
||||
var msg = string.Format(_totpSmsParams.Format, totp, new_expiration.ToString(_totpSmsParams.Expiration.Format, _totpSmsParams.Expiration.CultureInfo));
|
||||
await _dCache.SetDateTimeAsync(key, new_expiration, cToken: cToken);
|
||||
return (await _sender.SendSmsAsync(er_secret.PhoneNumber!, msg), new_expiration);
|
||||
}
|
||||
}
|
||||
|
||||
public bool VerifyTotp(string totpCode, string secretKey) => _authenticator
|
||||
.VerifyTotp(totpCode, secretKey, _totpSmsParams.TotpStep, _totpSmsParams.TotpVerificationWindow);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using DigitalData.Core.DTO;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeTypeService : BasicCRUDService<IEnvelopeTypeRepository, EnvelopeTypeDto, EnvelopeType, int>, IEnvelopeTypeService
|
||||
{
|
||||
private static readonly Guid CacheKey = Guid.NewGuid();
|
||||
|
||||
private readonly IMemoryCache _cache;
|
||||
|
||||
public EnvelopeTypeService(IEnvelopeTypeRepository repository, IMapper mapper, IMemoryCache cache)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
public override async Task<DataResult<IEnumerable<EnvelopeTypeDto>>> ReadAllAsync()
|
||||
=> await _cache.GetOrCreateAsync(CacheKey, async entry => await base.ReadAllAsync())
|
||||
?? Result.Fail<IEnumerable<EnvelopeTypeDto>>().Notice(LogLevel.Error, Flag.NotFound, "No cached envelope types are available in the database. If you have added any envelope types after the server started, please restart the server.");
|
||||
|
||||
}
|
||||
}
|
||||
40
EnvelopeGenerator.Application/Services/GTXSmsSender.cs
Normal file
40
EnvelopeGenerator.Application/Services/GTXSmsSender.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Abstractions.Client;
|
||||
using DigitalData.Core.Client;
|
||||
using EnvelopeGenerator.Application.Configurations;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services;
|
||||
|
||||
//TODO: move to DigitalData.Core
|
||||
public class GTXSmsSender : ISmsSender
|
||||
{
|
||||
private readonly IHttpClientService<GtxMessagingParams> _smsClient;
|
||||
|
||||
private readonly GtxMessagingParams _smsParams;
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public string ServiceProvider { get; }
|
||||
|
||||
public GTXSmsSender(IHttpClientService<GtxMessagingParams> smsClient, IOptions<GtxMessagingParams> smsParamsOptions, IMapper mapper)
|
||||
{
|
||||
_smsClient = smsClient;
|
||||
_smsParams = smsParamsOptions.Value;
|
||||
_mapper = mapper;
|
||||
ServiceProvider = GetType().Name.Replace("Service", string.Empty);
|
||||
}
|
||||
|
||||
public async Task<SmsResponse> SendSmsAsync(string recipient, string message)
|
||||
{
|
||||
return await _smsClient.FetchAsync(queryParams: new Dictionary<string, object?>()
|
||||
{
|
||||
{ _smsParams.RecipientQueryParamName, recipient },
|
||||
{ _smsParams.MessageQueryParamName, message }
|
||||
})
|
||||
.ThenAsync(res => res.Json<GtxMessagingResponse>())
|
||||
.ThenAsync(_mapper.Map<SmsResponse>);
|
||||
}
|
||||
}
|
||||
52
EnvelopeGenerator.Application/Services/ReceiverService.cs
Normal file
52
EnvelopeGenerator.Application/Services/ReceiverService.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.Core.Abstractions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class ReceiverService : CRUDService<IReceiverRepository, ReceiverCreateDto, ReceiverReadDto, ReceiverUpdateDto, Receiver, int>, IReceiverService
|
||||
{
|
||||
public ReceiverService(IReceiverRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<DataResult<ReceiverReadDto>> ReadByAsync(string? emailAddress = null, string? signature = null)
|
||||
{
|
||||
var rcv = await _repository.ReadByAsync(emailAddress: emailAddress, signature: signature);
|
||||
|
||||
if (rcv is null)
|
||||
return Result.Fail<ReceiverReadDto>();
|
||||
|
||||
return Result.Success(_mapper.Map<ReceiverReadDto>(rcv));
|
||||
}
|
||||
|
||||
public async Task<Result> DeleteByAsync(string? emailAddress = null, string? signature = null)
|
||||
{
|
||||
var rcv = await _repository.ReadByAsync(emailAddress: emailAddress, signature: signature);
|
||||
|
||||
if (rcv is null)
|
||||
return Result.Fail();
|
||||
|
||||
return await _repository.DeleteAsync(rcv) ? Result.Success() : Result.Fail();
|
||||
}
|
||||
|
||||
public virtual async Task<Result> UpdateAsync<TUpdateDto>(TUpdateDto updateDto) where TUpdateDto : IUnique<int>
|
||||
{
|
||||
var val = await _repository.ReadByIdAsync(updateDto.Id);
|
||||
if (val == null)
|
||||
{
|
||||
return Result.Fail().Notice(LogLevel.Warning, Flag.NotFound, $"{updateDto.Id} is not found in update process of {GetType()} entity.");
|
||||
}
|
||||
|
||||
var entity = _mapper.Map(updateDto, val);
|
||||
return (await _repository.UpdateAsync(entity)) ? Result.Success() : Result.Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using AutoMapper;
|
||||
using DigitalData.Core.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class UserReceiverService : BasicCRUDService<IUserReceiverRepository, UserReceiverDto, UserReceiver, int>, IUserReceiverService
|
||||
{
|
||||
public UserReceiverService(IUserReceiverRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
Public Class Constants
|
||||
|
||||
#Region "Status Fields"
|
||||
'http://wiki.dd/xwiki13/bin/view/Anwendungen/Produkt-Handbuch/Sonstiges/SignFlow/Envelope%20Status/
|
||||
Public Enum EnvelopeStatus
|
||||
Invalid = 0
|
||||
EnvelopeCreated = 1001
|
||||
@@ -17,7 +18,11 @@
|
||||
AccessCodeIncorrect = 2003
|
||||
DocumentOpened = 2004
|
||||
DocumentSigned = 2005
|
||||
DocumentForwarded = 4001
|
||||
SignatureConfirmed = 2006
|
||||
DocumentRejected = 2007
|
||||
EnvelopeShared = 2008
|
||||
EnvelopeViewed = 2009
|
||||
MessageInvitationSent = 3001 ' Wird von Trigger verwendet
|
||||
MessageAccessCodeSent = 3002
|
||||
MessageConfirmationSent = 3003
|
||||
@@ -25,6 +30,14 @@
|
||||
MessageCompletionSent = 3005
|
||||
End Enum
|
||||
|
||||
'TODO: standardize in xwiki
|
||||
Public Enum ReferenceType
|
||||
Receiver
|
||||
Sender
|
||||
System
|
||||
Unknown
|
||||
End Enum
|
||||
|
||||
Public Enum ElementStatus
|
||||
Created = 0
|
||||
End Enum
|
||||
@@ -64,8 +77,9 @@
|
||||
End Enum
|
||||
|
||||
Public Enum CertificationType
|
||||
ElectronicSignature = 1
|
||||
QualifiedSignature = 2
|
||||
AdvancedElectronicSignature = 1
|
||||
'ElectronicSignature = 1
|
||||
'QualifiedSignature = 2
|
||||
End Enum
|
||||
|
||||
Public Enum FinalEmailType
|
||||
@@ -85,8 +99,24 @@
|
||||
DocumentDeleted
|
||||
DocumentCompleted
|
||||
DocumentAccessCodeReceived
|
||||
DocumentShared
|
||||
TotpSecret
|
||||
End Enum
|
||||
|
||||
Public Enum EncodeType
|
||||
EnvelopeReceiver
|
||||
EnvelopeReceiverReadOnly
|
||||
Undefined
|
||||
DocumentForwarded
|
||||
DocumentShared
|
||||
End Enum
|
||||
#End Region
|
||||
|
||||
#Region "Role"
|
||||
Public NotInheritable Class ReceiverRole
|
||||
Public Const PreAuth As String = "PreAuth"
|
||||
Public Const FullyAuth As String = "FullyAuth"
|
||||
End Class
|
||||
#End Region
|
||||
|
||||
#Region "Constants"
|
||||
@@ -94,9 +124,10 @@
|
||||
Public Const DATABASE = "DATABASE"
|
||||
Public Const LOGCONFIG = "LOGCONFIG"
|
||||
Public Const GDPICTURE = "GDPICTURE"
|
||||
Public Const IGNORED_LABELS = "IgnoredLabels"
|
||||
|
||||
Public Const GREEN_300 = "#bbf7d0"
|
||||
Public Const RED_300 = "#fecaca"
|
||||
Public Const ORANGE_300 = "#fed7aa"
|
||||
#End Region
|
||||
End Class
|
||||
End Class
|
||||
@@ -1,7 +1,9 @@
|
||||
Public Class DbConfig
|
||||
Public Property ExternalProgramName As String = "Sign Flow"
|
||||
Public Property ExternalProgramName As String = "signFLOW"
|
||||
Public Property DocumentPathOrigin As String = ""
|
||||
Public Property DocumentPath As String = ""
|
||||
Public Property ExportPath As String = ""
|
||||
Public Property SendingProfile As Integer = 0
|
||||
Public Property SignatureHost As String = ""
|
||||
Public Property Default_TFA_Enabled As Boolean = False
|
||||
End Class
|
||||
|
||||
@@ -17,6 +17,8 @@ Public Class EmailData
|
||||
Public Property EnvelopeTitle As String = ""
|
||||
|
||||
Public Property EmailAttachment As String = ""
|
||||
Public Property ATT1_RELATED_ID As Long
|
||||
Public Property ATT1_REL_TYPE As String = ""
|
||||
|
||||
''' <summary>
|
||||
''' Constructor for sending email to receiver
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
Public Property Uuid As String = Guid.NewGuid.ToString()
|
||||
Public Property UseAccessCode As Boolean = False
|
||||
Public Property Language As String = "de-DE"
|
||||
Public Property CertificationType As Constants.CertificationType = Constants.CertificationType.ElectronicSignature
|
||||
|
||||
Public Property CertificationType As Constants.CertificationType = Constants.CertificationType.AdvancedElectronicSignature
|
||||
Public Property TFA_Enabled As Boolean = False
|
||||
Public Property SendReminderEmails As Boolean = False
|
||||
Public Property FirstReminderDays As Integer = 0
|
||||
Public Property ReminderIntervalDays As Integer = 0
|
||||
@@ -31,10 +31,10 @@
|
||||
Public Property Receivers As New List(Of EnvelopeReceiver)
|
||||
Public Property History As New List(Of EnvelopeHistoryEntry)
|
||||
Public Property EnvelopeType As EnvelopeType
|
||||
|
||||
Public Property DOC_RESULT As Byte()
|
||||
Public ReadOnly Property EnvelopeTypeTitle As String
|
||||
Get
|
||||
Return EnvelopeType.Title
|
||||
Return EnvelopeType?.Title
|
||||
End Get
|
||||
End Property
|
||||
|
||||
|
||||
@@ -19,10 +19,5 @@ Public Class EnvelopeDocument
|
||||
Public Property Filepath As String
|
||||
|
||||
Public Property PageCount As Integer
|
||||
|
||||
Public ReadOnly Property PageCountTranslated As String
|
||||
Get
|
||||
Return $"{PageCount} Seiten"
|
||||
End Get
|
||||
End Property
|
||||
End Class
|
||||
Public Property Byte_Data As Byte()
|
||||
End Class
|
||||
@@ -75,6 +75,7 @@ Public Class EnvelopeReceiver
|
||||
Public Property Sequence As Integer = 0
|
||||
Public Property PrivateMessage As String = ""
|
||||
Public Property AccessCode As String = ""
|
||||
Public Property PhoneNumber As String = ""
|
||||
|
||||
Public Function GetSignature() As String
|
||||
Return StringEx.GetChecksum(Email.ToUpper)
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
Public Property ContractType As Integer ' Unbenutzt
|
||||
|
||||
Public Property Language As String
|
||||
Public Property CertificationType As Constants.CertificationType = Constants.CertificationType.ElectronicSignature
|
||||
Public Property CertificationType As Constants.CertificationType = Constants.CertificationType.AdvancedElectronicSignature
|
||||
Public Property TFA_Enabled As Boolean = False
|
||||
Public Property SendReminderEmails As Boolean = False
|
||||
Public Property FirstReminderDays As Integer = 0
|
||||
Public Property ReminderIntervalDays As Integer = 0
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -63,22 +65,20 @@
|
||||
<Reference Include="DevExpress.XtraEditors.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
|
||||
<Reference Include="DevExpress.XtraGauges.v21.2.Core, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||
<Reference Include="DevExpress.XtraReports.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||
<Reference Include="DigitalData.Modules.Base, Version=1.3.4.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\DDModules\Base\bin\Debug\DigitalData.Modules.Base.dll</HintPath>
|
||||
<Reference Include="DigitalData.Modules.Base">
|
||||
<HintPath>..\..\2_DLL Projekte\DDModules\Base\bin\Debug\DigitalData.Modules.Base.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Modules.Config">
|
||||
<HintPath>..\..\DDModules\Config\bin\Debug\DigitalData.Modules.Config.dll</HintPath>
|
||||
<HintPath>..\..\2_DLL Projekte\DDModules\Config\bin\Debug\DigitalData.Modules.Config.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Modules.Database">
|
||||
<HintPath>..\..\DDModules\Database\bin\Debug\DigitalData.Modules.Database.dll</HintPath>
|
||||
<HintPath>..\..\2_DLL Projekte\DDModules\Database\bin\Debug\DigitalData.Modules.Database.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Modules.Logging, Version=2.6.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\DDModules\Logging\bin\Debug\DigitalData.Modules.Logging.dll</HintPath>
|
||||
<Reference Include="DigitalData.Modules.Logging">
|
||||
<HintPath>..\..\2_DLL Projekte\DDModules\Logging\bin\Debug\DigitalData.Modules.Logging.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="GdPicture.NET.14">
|
||||
<HintPath>D:\ProgramFiles\GdPicture.NET 14\Redist\GdPicture.NET (.NET Framework 4.5)\GdPicture.NET.14.dll</HintPath>
|
||||
<Reference Include="GdPicture.NET.14, Version=14.2.90.0, Culture=neutral, PublicKeyToken=f52a2e60ad468dbb, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\GdPicture.14.2.90\lib\net462\GdPicture.NET.14.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
@@ -220,6 +220,8 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Model.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Strings\Model.vb" />
|
||||
<Compile Include="TempFiles.vb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="My Project\licenses.licx" />
|
||||
@@ -241,11 +243,13 @@
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Envelope.en.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Strings\Envelope.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Envelope1.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Strings\Email.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
@@ -256,14 +260,17 @@
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Model.en.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Strings\Model.resx">
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Model.Designer.vb</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="My Project\Application.myapp">
|
||||
<Generator>MyApplicationCodeGenerator</Generator>
|
||||
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||
@@ -284,4 +291,11 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||
<Import Project="..\packages\GdPicture.runtimes.windows.14.2.90\build\net462\GdPicture.runtimes.windows.targets" Condition="Exists('..\packages\GdPicture.runtimes.windows.14.2.90\build\net462\GdPicture.runtimes.windows.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\GdPicture.runtimes.windows.14.2.90\build\net462\GdPicture.runtimes.windows.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\GdPicture.runtimes.windows.14.2.90\build\net462\GdPicture.runtimes.windows.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,9 +1,28 @@
|
||||
Imports System.Drawing
|
||||
Imports System.IO
|
||||
Imports System.Security.Cryptography
|
||||
Imports System.Text
|
||||
Imports DevExpress.Utils.Svg
|
||||
Imports EnvelopeGenerator.Common.Constants
|
||||
|
||||
Public Class Helpers
|
||||
Private Shared key As String = "$xzBvyPETUS&amm8)D8x#)f;4%;?[BPd" ' Passwort-Schlüssel (16, 24, or 32 bytes)
|
||||
Private Shared iv As String = "1wN&e[zrQ6_B7X/0" ' Initialisierungsvektor (16 bytes)
|
||||
|
||||
' Entschlüsselungsfunktion
|
||||
Public Shared Function Decrypt(cipherText As String) As String
|
||||
Dim aesAlg As Aes = Aes.Create()
|
||||
aesAlg.Key = Encoding.UTF8.GetBytes(key)
|
||||
aesAlg.IV = Encoding.UTF8.GetBytes(iv)
|
||||
Dim decryptor As ICryptoTransform = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV)
|
||||
Dim cipherBytes As Byte() = Convert.FromBase64String(cipherText)
|
||||
Dim msDecrypt As New IO.MemoryStream(cipherBytes)
|
||||
Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
|
||||
Using srDecrypt As New IO.StreamReader(csDecrypt)
|
||||
Return srDecrypt.ReadToEnd()
|
||||
End Using
|
||||
End Using
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Encodes the EnvelopeUUID and the ReceiverSignature into an EnvelopeKey
|
||||
|
||||
@@ -7,8 +7,9 @@ Imports System.Security.Cryptography
|
||||
Imports System.IO
|
||||
Imports EnvelopeGenerator.Common.Jobs.FinalizeDocument.FinalizeDocumentExceptions
|
||||
Imports EnvelopeGenerator.Common.Jobs.FinalizeDocument
|
||||
Imports EnvelopeGenerator.Common.My.Resources
|
||||
Imports EnvelopeGenerator.Common.Constants
|
||||
Imports DevExpress.DataProcessing
|
||||
Imports System.Data.SqlClient
|
||||
|
||||
Namespace Jobs
|
||||
Public Class FinalizeDocumentJob
|
||||
@@ -32,12 +33,16 @@ Namespace Jobs
|
||||
Private PDFMerger As PDFMerger
|
||||
Private ReportCreator As ReportCreator
|
||||
|
||||
Private ReadOnly CompleteWaitTimeInMinutes As Integer = 5
|
||||
Private ReadOnly CompleteWaitTime As Integer = 1
|
||||
Private ParentFolderUID As String = ""
|
||||
Private myTempFiles As TempFiles
|
||||
|
||||
Private Class EnvelopeData
|
||||
Public EnvelopeId As Integer
|
||||
Public EnvelopeUUID As String
|
||||
Public DocumentPath As String
|
||||
Public AnnotationData As List(Of String)
|
||||
Public DocAsByte As Byte()
|
||||
|
||||
End Class
|
||||
|
||||
@@ -45,7 +50,8 @@ Namespace Jobs
|
||||
Dim oGdPictureKey As String = pContext.MergedJobDataMap.Item(Constants.GDPICTURE)
|
||||
LogConfig = pContext.MergedJobDataMap.Item(Constants.LOGCONFIG)
|
||||
Logger = LogConfig.GetLogger()
|
||||
|
||||
myTempFiles = New TempFiles(LogConfig)
|
||||
myTempFiles.Create()
|
||||
Dim JobId = pContext.JobDetail.Key
|
||||
Logger.Info("Starting job {0}", JobId)
|
||||
|
||||
@@ -68,7 +74,8 @@ Namespace Jobs
|
||||
InitializeServices(oState)
|
||||
|
||||
Logger.Debug("Loading PDFBurner..")
|
||||
PDFBurner = New PDFBurner(LogConfig, oGdPictureKey)
|
||||
Dim ignoredLabels As List(Of String) = pContext.MergedJobDataMap.Item(Constants.IGNORED_LABELS)
|
||||
PDFBurner = New PDFBurner(LogConfig, oGdPictureKey, ignoredLabels)
|
||||
|
||||
Logger.Debug("Loading PDFMerger..")
|
||||
PDFMerger = New PDFMerger(LogConfig, oGdPictureKey)
|
||||
@@ -76,11 +83,15 @@ Namespace Jobs
|
||||
Logger.Debug("Loading ReportCreator..")
|
||||
ReportCreator = New ReportCreator(LogConfig, oState)
|
||||
|
||||
Config.DocumentPath = Config.DocumentPath
|
||||
|
||||
Logger.Debug("DocumentPath: [{0}]", Config.DocumentPath)
|
||||
|
||||
|
||||
Logger.Debug("ExportPath: [{0}]", Config.ExportPath)
|
||||
|
||||
Dim oCompleteStatus As Integer = Constants.EnvelopeStatus.EnvelopeCompletelySigned
|
||||
Dim oSql = $"SELECT * FROM TBSIG_ENVELOPE WHERE STATUS = {oCompleteStatus} AND DATEDIFF(minute, CHANGED_WHEN, GETDATE()) >= {CompleteWaitTimeInMinutes}"
|
||||
Dim oSql = $"SELECT * FROM TBSIG_ENVELOPE WHERE STATUS = {oCompleteStatus} AND DATEDIFF(minute, CHANGED_WHEN, GETDATE()) >= {CompleteWaitTime} ORDER BY GUID"
|
||||
Dim oTable = Database.GetDatatable(oSql)
|
||||
|
||||
Dim oEnvelopeIds As List(Of Integer) = oTable.Rows.Cast(Of DataRow).
|
||||
@@ -88,81 +99,87 @@ Namespace Jobs
|
||||
Cast(Of Integer).
|
||||
ToList()
|
||||
|
||||
Logger.Info("Found [{0}] completed envelopes.", oEnvelopeIds.Count)
|
||||
If oEnvelopeIds.Count > 0 Then
|
||||
Logger.Info("Found [{0}] completed envelopes.", oEnvelopeIds.Count)
|
||||
End If
|
||||
|
||||
Dim oTotal As Integer = oEnvelopeIds.Count
|
||||
Dim oCurrent As Integer = 1
|
||||
|
||||
For Each oId In oEnvelopeIds
|
||||
|
||||
Logger.Info("Finalizing Envelope [{0}] ({1}/{2})", oId, oCurrent, oTotal)
|
||||
|
||||
Logger.Debug("Loading Envelope..")
|
||||
Dim oEnvelope = EnvelopeModel.GetById(oId)
|
||||
|
||||
If oEnvelope Is Nothing Then
|
||||
Logger.Warn("Envelope could not be loaded for Id [{0}]!", oId)
|
||||
Throw New ArgumentNullException("EnvelopeData")
|
||||
End If
|
||||
|
||||
Logger.Debug("Loading Envelope Data..")
|
||||
Dim oEnvelopeData = GetEnvelopeData(oId)
|
||||
|
||||
If oEnvelopeData Is Nothing Then
|
||||
Logger.Warn("EnvelopeData could not be loaded for Id [{0}]!", oId)
|
||||
Throw New ArgumentNullException("EnvelopeData")
|
||||
End If
|
||||
|
||||
Logger.Debug("Burning Annotations to pdf")
|
||||
Dim oBurnedDocument As Byte() = BurnAnnotationsToPdf(oEnvelopeData)
|
||||
If oBurnedDocument Is Nothing Then
|
||||
Logger.Warn("Document could not be finalized!")
|
||||
Throw New ApplicationException("Document could not be finalized")
|
||||
End If
|
||||
|
||||
If ActionService.CreateReport(oEnvelope) = False Then
|
||||
Logger.Warn("Document Report could not be created!")
|
||||
Throw New ApplicationException("Document Report could not be created")
|
||||
End If
|
||||
|
||||
Logger.Debug("Creating report..")
|
||||
Dim oReport As Byte() = ReportCreator.CreateReport(oEnvelope)
|
||||
Logger.Debug("Report created.")
|
||||
|
||||
Logger.Debug("Merging documents..")
|
||||
Dim oMergedDocument As Byte() = PDFMerger.MergeDocuments(oBurnedDocument, oReport)
|
||||
Logger.Debug("Documents merged.")
|
||||
|
||||
Dim oOutputDirectoryPath = Config.ExportPath
|
||||
Dim oOutputFilePath = Path.Combine(oOutputDirectoryPath, $"{oEnvelope.Uuid}.pdf")
|
||||
|
||||
Logger.Info("Writing finalized Pdf to disk..")
|
||||
Logger.Info("Output path is [{0}]", oOutputFilePath)
|
||||
|
||||
Try
|
||||
File.WriteAllBytes(oOutputFilePath, oMergedDocument)
|
||||
Dim oEnvelope = EnvelopeModel.GetById(oId)
|
||||
If oEnvelope Is Nothing Then
|
||||
Logger.Warn("Envelope could not be loaded for Id [{0}]!", oId)
|
||||
Throw New ArgumentNullException("EnvelopeData")
|
||||
End If
|
||||
Logger.Debug("Loading Envelope Data..")
|
||||
Dim oEnvelopeData = GetEnvelopeData(oId)
|
||||
|
||||
If oEnvelopeData Is Nothing Then
|
||||
Logger.Warn("EnvelopeData could not be loaded for Id [{0}]!", oId)
|
||||
Throw New ArgumentNullException("EnvelopeData")
|
||||
End If
|
||||
Logger.Debug("Burning Annotations to pdf ...")
|
||||
Dim oBurnedDocument As Byte() = BurnAnnotationsToPdf(oEnvelopeData)
|
||||
If oBurnedDocument Is Nothing Then
|
||||
Logger.Warn("Document could not be finalized!")
|
||||
Throw New ApplicationException("Document could not be finalized")
|
||||
End If
|
||||
|
||||
If ActionService.CreateReport(oEnvelope) = False Then
|
||||
Logger.Warn("Document Report could not be created!")
|
||||
Throw New ApplicationException("Document Report could not be created")
|
||||
End If
|
||||
|
||||
Logger.Debug("Creating report..")
|
||||
Dim oReport As Byte() = ReportCreator.CreateReport(oEnvelope)
|
||||
Logger.Debug("Report created!")
|
||||
|
||||
Logger.Debug("Merging documents ...")
|
||||
Dim oMergedDocument As Byte() = PDFMerger.MergeDocuments(oBurnedDocument, oReport)
|
||||
Logger.Debug("Documents merged!")
|
||||
|
||||
Dim oOutputDirectoryPath = Path.Combine(Config.ExportPath, ParentFolderUID)
|
||||
If Not Directory.Exists(oOutputDirectoryPath) Then
|
||||
Directory.CreateDirectory(oOutputDirectoryPath)
|
||||
End If
|
||||
Dim oOutputFilePath = Path.Combine(oOutputDirectoryPath, $"{oEnvelope.Uuid}.pdf")
|
||||
Logger.Info("Writing finalized Pdf to disk..")
|
||||
Logger.Info("Output path is [{0}]", oOutputFilePath)
|
||||
|
||||
Try
|
||||
File.WriteAllBytes(oOutputFilePath, oMergedDocument)
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Could not export final document to disk!")
|
||||
Throw New ExportDocumentException("Could not export final document to disk!", ex)
|
||||
End Try
|
||||
|
||||
Logger.Info("Writing EB-bytes to database...")
|
||||
Update_File_DB(oOutputFilePath, oEnvelope.Id)
|
||||
|
||||
Logger.Info("Sending finalized report-mails..")
|
||||
If SendFinalEmails(oEnvelope) = False Then ', oOutputFilePath
|
||||
Throw New ApplicationException("Final emails could not be sent!")
|
||||
End If
|
||||
Logger.Debug("Setting envelope status..")
|
||||
If ActionService.FinalizeEnvelope(oEnvelope) = False Then
|
||||
Logger.Warn("Envelope could not be finalized!")
|
||||
Throw New ApplicationException("Envelope could not be finalized")
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Could not export final document to disk!")
|
||||
Throw New ExportDocumentException("Could not export final document to disk!", ex)
|
||||
Logger.Warn($"Unhandled exception while working envelope [{oId}] - [{ex.Message}]")
|
||||
End Try
|
||||
|
||||
Logger.Info("Sending final Emails..")
|
||||
|
||||
If SendFinalEmails(oEnvelope, oOutputFilePath) = False Then
|
||||
Throw New ApplicationException("Final emails could not be sent!")
|
||||
End If
|
||||
|
||||
Logger.Debug("Setting envelope status..")
|
||||
If ActionService.FinalizeEnvelope(oEnvelope) = False Then
|
||||
Logger.Warn("Envelope could not be finalized!")
|
||||
Throw New ApplicationException("Envelope could not be finalized")
|
||||
End If
|
||||
|
||||
oCurrent += 1
|
||||
Logger.Info("Envelope finalized!")
|
||||
|
||||
Next
|
||||
|
||||
Logger.Info("Completed job {0} successfully!", JobId)
|
||||
Logger.Debug("Completed job {0} successfully!", JobId)
|
||||
Catch ex As MergeDocumentException
|
||||
Logger.Warn("Certificate Document job failed at step: Merging documents!")
|
||||
Logger.Error(ex)
|
||||
@@ -180,34 +197,119 @@ Namespace Jobs
|
||||
|
||||
Return Task.FromResult(True)
|
||||
End Function
|
||||
Private Sub Update_File_DB(pFilePath As String, pEnvelopeID As Long)
|
||||
Dim SqlCom As SqlCommand
|
||||
Dim imageData As Byte()
|
||||
Dim sFileName As String
|
||||
Dim qry As String
|
||||
|
||||
Private Function SendFinalEmails(pEnvelope As Envelope, pAttachment As String) As Boolean
|
||||
Try
|
||||
'Read Image Bytes into a byte array
|
||||
'Initialize SQL Server Connection
|
||||
|
||||
'Convert File to bytes Array
|
||||
imageData = ReadFile(pFilePath)
|
||||
If Not IsNothing(imageData) Then
|
||||
sFileName = System.IO.Path.GetFileName(pFilePath)
|
||||
'Set insert query
|
||||
qry = $"UPDATE TBSIG_ENVELOPE SET DOC_RESULT = @ImageData WHERE GUID = {pEnvelopeID}"
|
||||
'Initialize SqlCommand object for insert.
|
||||
SqlCom = New SqlCommand(qry, Database.GetConnection)
|
||||
'We are passing File Name and Image byte data as sql parameters.
|
||||
SqlCom.Parameters.Add(New SqlParameter("@ImageData", DirectCast(imageData, Object)))
|
||||
'Execute the Query
|
||||
SqlCom.ExecuteNonQuery()
|
||||
End If
|
||||
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
End Try
|
||||
End Sub
|
||||
'Open file in to a filestream and read data in a byte array.
|
||||
Private Function ReadFile(ByVal sPath As String) As Byte()
|
||||
'Initialize byte array with a null value initially.
|
||||
Dim data As Byte() = Nothing
|
||||
'Use FileInfo object to get file size.
|
||||
Dim fInfo As New FileInfo(sPath)
|
||||
Dim numBytes As Long = fInfo.Length
|
||||
'Open FileStream to read file
|
||||
Dim fStream As New FileStream(sPath, FileMode.Open, FileAccess.Read)
|
||||
'Use BinaryReader to read file stream into byte array.
|
||||
Dim br As New BinaryReader(fStream)
|
||||
'When you use BinaryReader, you need to supply number of bytes to read from file.
|
||||
'In this case we want to read entire file. So supplying total number of bytes.
|
||||
data = br.ReadBytes(CInt(numBytes))
|
||||
Return data
|
||||
End Function
|
||||
'Private Function NetUse_Command(pDestinationPath As String, pUsername As String, pPassword As String)
|
||||
' Dim oDectryptedPW = Helpers.Decrypt(My.Settings.NetUse_PW)
|
||||
' Dim netUseCommand As String = $"net use {pDestinationPath} /user:{pUsername} {oDectryptedPW}"
|
||||
' Logger.Debug("EXECUTING NetUse_Command for " & pDestinationPath)
|
||||
' Dim processInfo As New ProcessStartInfo("cmd.exe", $"/C {netUseCommand}")
|
||||
' processInfo.RedirectStandardOutput = True
|
||||
' processInfo.UseShellExecute = False
|
||||
' processInfo.CreateNoWindow = True
|
||||
|
||||
' Using process As Process = Process.Start(processInfo)
|
||||
' process.WaitForExit()
|
||||
|
||||
' ' Prüfe den Rückgabewert des net use Befehls
|
||||
' If process.ExitCode = 0 Then
|
||||
' Return True
|
||||
' Else
|
||||
' Return False
|
||||
' End If
|
||||
' End Using
|
||||
'End Function
|
||||
|
||||
'Private Function Clean_DNZ_PAth(pSourcePath As String) As Boolean
|
||||
' Dim oFilename = System.IO.Path.GetFileName(pSourcePath)
|
||||
|
||||
' Logger.Debug("## Starting Clean_DNZ_PAth ...")
|
||||
' Logger.Debug("## pSourcePath {0}", pSourcePath)
|
||||
|
||||
' Dim oDirectorySource = Path.Combine(pSourcePath, ParentFolderUID)
|
||||
|
||||
' Try
|
||||
' Logger.Debug($"Deleting oDirectorySource {oDirectorySource} ...")
|
||||
' Directory.Delete(oDirectorySource, True)
|
||||
' Console.WriteLine($"Folder successfully deleted!")
|
||||
' Logger.Debug($"...Deleted!")
|
||||
' Return True
|
||||
' Catch ex As Exception
|
||||
' Logger.Error(ex)
|
||||
' Return False
|
||||
' End Try
|
||||
|
||||
|
||||
'End Function
|
||||
Private Function SendFinalEmails(pEnvelope As Envelope) As Boolean ', pAttachment As String
|
||||
Dim oMailToCreator = pEnvelope.FinalEmailToCreator
|
||||
Dim oMailToReceivers = pEnvelope.FinalEmailToReceivers
|
||||
|
||||
If oMailToCreator <> FinalEmailType.No Then
|
||||
Logger.Debug("Sending email to creator..")
|
||||
SendFinalEmailToCreator(pEnvelope, pAttachment)
|
||||
Logger.Debug("Sending email to creator ...")
|
||||
SendFinalEmailToCreator(pEnvelope) ', pAttachment
|
||||
End If
|
||||
|
||||
If oMailToReceivers <> FinalEmailType.No Then
|
||||
Logger.Debug("Sending emails to receivers..")
|
||||
SendFinalEmailToReceivers(pEnvelope, pAttachment)
|
||||
SendFinalEmailToReceivers(pEnvelope) ', pAttachment
|
||||
End If
|
||||
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Private Function SendFinalEmailToCreator(pEnvelope As Envelope, pAttachment As String) As Boolean
|
||||
Private Function SendFinalEmailToCreator(pEnvelope As Envelope) As Boolean ', pAttachment As String
|
||||
Dim oIncludeAttachment = SendFinalEmailWithAttachment(pEnvelope.FinalEmailToCreator)
|
||||
Dim oAttachment = String.Empty
|
||||
' Dim oAttachment = String.Empty
|
||||
|
||||
Logger.Debug("Attachment included: [{0}]", oIncludeAttachment)
|
||||
If oIncludeAttachment Then
|
||||
oAttachment = pAttachment
|
||||
'oAttachment = pAttachment
|
||||
End If
|
||||
|
||||
If ActionService.CompleteEnvelope(pEnvelope, oAttachment) = False Then
|
||||
If ActionService.CompleteEnvelope(pEnvelope) = False Then ', oAttachment
|
||||
Logger.Error("Envelope could not be completed for receiver [{0}]", pEnvelope.User.Email)
|
||||
Return False
|
||||
End If
|
||||
@@ -215,17 +317,18 @@ Namespace Jobs
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Private Function SendFinalEmailToReceivers(pEnvelope As Envelope, pAttachment As String) As Boolean
|
||||
Private Function SendFinalEmailToReceivers(pEnvelope As Envelope) As Boolean ', pAttachment As String
|
||||
Dim oIncludeAttachment = SendFinalEmailWithAttachment(pEnvelope.FinalEmailToReceivers)
|
||||
Dim oAttachment = String.Empty
|
||||
'Dim oAttachment = String.Empty
|
||||
|
||||
Logger.Debug("Attachment included: [{0}]", oIncludeAttachment)
|
||||
If oIncludeAttachment Then
|
||||
oAttachment = pAttachment
|
||||
|
||||
' oAttachment = pAttachment
|
||||
End If
|
||||
|
||||
For Each oReceiver In pEnvelope.Receivers
|
||||
If ActionService.CompleteEnvelope(pEnvelope, oReceiver, oAttachment) = False Then
|
||||
If ActionService.CompleteEnvelope(pEnvelope, oReceiver) = False Then ', oAttachment
|
||||
Logger.Error("Envelope could not be completed for receiver [{0}]", oReceiver.Email)
|
||||
Return False
|
||||
End If
|
||||
@@ -242,27 +345,50 @@ Namespace Jobs
|
||||
End If
|
||||
End Function
|
||||
|
||||
Private Function BurnAnnotationsToPdf(pData As EnvelopeData) As Byte()
|
||||
Dim pEnvelopeId = pData.EnvelopeId
|
||||
Private Function BurnAnnotationsToPdf(pEnvelopeData As EnvelopeData) As Byte()
|
||||
Dim pEnvelopeId = pEnvelopeData.EnvelopeId
|
||||
|
||||
Logger.Info("Burning [{0}] signatures", pData.AnnotationData.Count)
|
||||
Dim oAnnotations = pData.AnnotationData
|
||||
Dim oInputPath = pData.DocumentPath
|
||||
Logger.Info($"Burning [{pEnvelopeData.AnnotationData.Count}] signatures")
|
||||
Dim oAnnotations = pEnvelopeData.AnnotationData
|
||||
Dim oInputPath = ""
|
||||
If IsNothing(pEnvelopeData.DocAsByte) Then
|
||||
oInputPath = pEnvelopeData.DocumentPath
|
||||
Logger.Info($"Input path: [{oInputPath}]")
|
||||
Else
|
||||
Logger.Info($"we got bytes..")
|
||||
oInputPath = Config.DocumentPathOrigin
|
||||
Logger.Info($"oInputPath: {Config.DocumentPathOrigin}")
|
||||
End If
|
||||
|
||||
Logger.Info("Input path: [{0}]", oInputPath)
|
||||
|
||||
If IsNothing(pEnvelopeData.DocAsByte) Then
|
||||
Dim oDirectorySource As String = Path.GetDirectoryName(oInputPath)
|
||||
Dim split As String() = oDirectorySource.Split("\")
|
||||
ParentFolderUID = split(split.Length - 1)
|
||||
Else
|
||||
ParentFolderUID = pEnvelopeData.EnvelopeUUID
|
||||
End If
|
||||
|
||||
|
||||
Logger.Info("ParentFolderUID: [{0}]", ParentFolderUID)
|
||||
Dim oInputDocumentBuffer As Byte()
|
||||
Try
|
||||
oInputDocumentBuffer = File.ReadAllBytes(oInputPath)
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw New BurnAnnotationException("Source document could not be read from disk!", ex)
|
||||
End Try
|
||||
If Not IsNothing(pEnvelopeData.DocAsByte) Then
|
||||
oInputDocumentBuffer = pEnvelopeData.DocAsByte
|
||||
Else
|
||||
Try
|
||||
oInputDocumentBuffer = File.ReadAllBytes(oInputPath)
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw New BurnAnnotationException("Source document could not be read from disk!", ex)
|
||||
End Try
|
||||
End If
|
||||
|
||||
|
||||
Return PDFBurner.BurnInstantJSONAnnotationsToPDF(oInputDocumentBuffer, oAnnotations)
|
||||
End Function
|
||||
|
||||
Private Function GetEnvelopeData(pEnvelopeId As Integer) As EnvelopeData
|
||||
Dim oSql = $"SELECT T.GUID, T2.FILEPATH FROM [dbo].[TBSIG_ENVELOPE] T
|
||||
Dim oSql = $"SELECT T.GUID, T.ENVELOPE_UUID,T2.FILEPATH, T2.BYTE_DATA FROM [dbo].[TBSIG_ENVELOPE] T
|
||||
JOIN TBSIG_ENVELOPE_DOCUMENT T2 ON T.GUID = T2.ENVELOPE_ID
|
||||
WHERE T.GUID = {pEnvelopeId}"
|
||||
Dim oTable As DataTable = Database.GetDatatable(oSql)
|
||||
@@ -275,7 +401,9 @@ Namespace Jobs
|
||||
Dim oData As New EnvelopeData With {
|
||||
.EnvelopeId = pEnvelopeId,
|
||||
.DocumentPath = oRow.ItemEx("FILEPATH", ""),
|
||||
.AnnotationData = oAnnotationData
|
||||
.AnnotationData = oAnnotationData,
|
||||
.DocAsByte = DirectCast(oRow.Item("BYTE_DATA"), Byte()),
|
||||
.EnvelopeUUID = oRow.ItemEx("ENVELOPE_UUID", "")
|
||||
}
|
||||
|
||||
Logger.Debug("Document path: [{0}]", oData.DocumentPath)
|
||||
|
||||
@@ -15,14 +15,18 @@ Namespace Jobs.FinalizeDocument
|
||||
|
||||
Private Const ANNOTATION_TYPE_IMAGE = "pspdfkit/image"
|
||||
Private Const ANNOTATION_TYPE_INK = "pspdfkit/ink"
|
||||
Private Const ANNOTATION_TYPE_WIDGET = "pspdfkit/widget"
|
||||
Private Property _ignoredLabels As List(Of String)
|
||||
|
||||
Public Sub New(pLogConfig As LogConfig, pGDPictureLicenseKey As String)
|
||||
Public Sub New(pLogConfig As LogConfig, pGDPictureLicenseKey As String, ignoredLabels As List(Of String))
|
||||
MyBase.New(pLogConfig)
|
||||
|
||||
LicenseManager = New LicenseManager()
|
||||
LicenseManager.RegisterKEY(pGDPictureLicenseKey)
|
||||
|
||||
Manager = New AnnotationManager()
|
||||
|
||||
_ignoredLabels = ignoredLabels
|
||||
End Sub
|
||||
|
||||
Public Function BurnInstantJSONAnnotationsToPDF(pSourceBuffer As Byte(), pInstantJSONList As List(Of String)) As Byte()
|
||||
@@ -37,11 +41,11 @@ Namespace Jobs.FinalizeDocument
|
||||
|
||||
For Each oJSON In pInstantJSONList
|
||||
If AddInstantJSONAnnotationToPDF(oJSON) = False Then
|
||||
Logger.Warn($"Error in AddInstantJSONAnnotationToPDF - oJson: ")
|
||||
Logger.Warn(oJSON)
|
||||
Throw New BurnAnnotationException($"Adding Annotation failed")
|
||||
End If
|
||||
Next
|
||||
|
||||
|
||||
oResult = Manager.BurnAnnotationsToPage(RemoveInitialAnnots:=True, VectorMode:=True)
|
||||
If oResult <> GdPictureStatus.OK Then
|
||||
Throw New BurnAnnotationException($"Could not burn annotations to file: [{oResult}]")
|
||||
@@ -70,6 +74,7 @@ Namespace Jobs.FinalizeDocument
|
||||
Dim oAnnotationData = JsonConvert.DeserializeObject(Of AnnotationData)(pInstantJSON)
|
||||
|
||||
For Each oAnnotation In oAnnotationData.annotations
|
||||
Logger.Debug("Adding AnnotationID: " + oAnnotation.id)
|
||||
Select Case oAnnotation.type
|
||||
Case ANNOTATION_TYPE_IMAGE
|
||||
AddImageAnnotation(oAnnotation, oAnnotationData.attachments)
|
||||
@@ -77,6 +82,12 @@ Namespace Jobs.FinalizeDocument
|
||||
Case ANNOTATION_TYPE_INK
|
||||
AddInkAnnotation(oAnnotation)
|
||||
|
||||
Case ANNOTATION_TYPE_WIDGET
|
||||
'Add form field values
|
||||
Dim formFieldValue = oAnnotationData.formFieldValues.FirstOrDefault(Function(fv) fv.name = oAnnotation.id)
|
||||
If formFieldValue IsNot Nothing AndAlso Not _ignoredLabels.Contains(formFieldValue.value) Then
|
||||
AddFormFieldValue(oAnnotation, formFieldValue)
|
||||
End If
|
||||
End Select
|
||||
Next
|
||||
|
||||
@@ -137,6 +148,33 @@ Namespace Jobs.FinalizeDocument
|
||||
|
||||
End Function
|
||||
|
||||
Private Function AddFormFieldValue(pAnnotation As Annotation, formFieldValue As FormFieldValue) As Boolean
|
||||
Try
|
||||
' Convert pixels to Inches
|
||||
Dim oBounds = pAnnotation.bbox.Select(AddressOf ToInches).ToList()
|
||||
|
||||
Dim oX = oBounds.Item(0)
|
||||
Dim oY = oBounds.Item(1)
|
||||
Dim oWidth = oBounds.Item(2)
|
||||
Dim oHeight = oBounds.Item(3)
|
||||
|
||||
Manager.SelectPage(pAnnotation.pageIndex + 1)
|
||||
' Add the text annotation
|
||||
Dim ant = Manager.AddTextAnnot(oX, oY, oWidth, oHeight, formFieldValue.value)
|
||||
|
||||
' Set the font properties
|
||||
ant.FontName = "Arial"
|
||||
ant.FontSize = 8
|
||||
ant.FontStyle = FontStyle.Italic
|
||||
Manager.SaveAnnotationsToPage()
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Could not add image annotation!")
|
||||
Logger.Error(ex)
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private Function ToPointF(pPoints As List(Of Single)) As PointF
|
||||
Dim oPoints = pPoints.Select(AddressOf ToInches).ToList()
|
||||
Return New PointF(oPoints.Item(0), oPoints.Item(1))
|
||||
@@ -153,6 +191,7 @@ Namespace Jobs.FinalizeDocument
|
||||
Friend Class AnnotationData
|
||||
Public Property annotations As List(Of Annotation)
|
||||
Public Property attachments As Dictionary(Of String, Attachment)
|
||||
Public Property formFieldValues As List(Of FormFieldValue)
|
||||
End Class
|
||||
|
||||
Friend Class Annotation
|
||||
@@ -174,5 +213,10 @@ Namespace Jobs.FinalizeDocument
|
||||
Public Property binary As String
|
||||
Public Property contentType As String
|
||||
End Class
|
||||
|
||||
Friend Class FormFieldValue
|
||||
Public Property name As String
|
||||
Public Property value As String
|
||||
End Class
|
||||
End Class
|
||||
End Namespace
|
||||
|
||||
@@ -16,11 +16,13 @@ Public Class ConfigModel
|
||||
Dim oRow As DataRow = oTable.Rows.Item(0)
|
||||
|
||||
Return New DbConfig() With {
|
||||
.DocumentPath = oRow.ItemEx("DOCUMENT_PATH", ""),
|
||||
.ExportPath = oRow.ItemEx("EXPORT_PATH", ""),
|
||||
.SendingProfile = oRow.ItemEx("SENDING_PROFILE", 0),
|
||||
.SignatureHost = oRow.ItemEx("SIGNATURE_HOST", ""),
|
||||
.ExternalProgramName = oRow.ItemEx("EXTERNAL_PROGRAM_NAME", "")
|
||||
.DocumentPath = oRow.ItemEx("DOCUMENT_PATH", ""),
|
||||
.DocumentPathOrigin = oRow.ItemEx("DOCUMENT_PATH", ""),
|
||||
.ExportPath = oRow.ItemEx("EXPORT_PATH", ""),
|
||||
.SendingProfile = oRow.ItemEx("SENDING_PROFILE", 0),
|
||||
.SignatureHost = oRow.ItemEx("SIGNATURE_HOST", ""),
|
||||
.ExternalProgramName = oRow.ItemEx("EXTERNAL_PROGRAM_NAME", ""),
|
||||
.Default_TFA_Enabled = oRow.ItemEx("DEF_TFA_ENABLED", False)
|
||||
}
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
|
||||
@@ -24,7 +24,8 @@ Public Class DocumentModel
|
||||
.Filepath = pRow.ItemEx("FILEPATH", ""),
|
||||
.FileNameOriginal = pRow.ItemEx("FILENAME_ORIGINAL", ""),
|
||||
.IsTempFile = False,
|
||||
.Elements = ElementModel.List(oDocumentId, pReceiverId)
|
||||
.Elements = ElementModel.List(oDocumentId, pReceiverId),
|
||||
.Byte_Data = DirectCast(pRow.Item("BYTE_DATA"), Byte())
|
||||
}
|
||||
End Function
|
||||
|
||||
@@ -79,18 +80,21 @@ Public Class DocumentModel
|
||||
([FILENAME]
|
||||
,[FILENAME_ORIGINAL]
|
||||
,[FILEPATH]
|
||||
,[ENVELOPE_ID])
|
||||
,[ENVELOPE_ID]
|
||||
,[BYTE_DATA])
|
||||
VALUES
|
||||
(@FILENAME
|
||||
,@FILENAME_ORIGINAL
|
||||
,@FILEPATH
|
||||
,@ENVELOPE_ID)"
|
||||
,@ENVELOPE_ID
|
||||
,@BYTE_DATA)"
|
||||
|
||||
Dim oCommand As New SqlCommand(oSql)
|
||||
oCommand.Parameters.Add("FILENAME", SqlDbType.NVarChar).Value = pDocument.Filename
|
||||
oCommand.Parameters.Add("FILENAME_ORIGINAL", SqlDbType.NVarChar).Value = pDocument.FileNameOriginal
|
||||
oCommand.Parameters.Add("FILEPATH", SqlDbType.NVarChar).Value = pDocument.Filepath
|
||||
oCommand.Parameters.Add("ENVELOPE_ID", SqlDbType.Int).Value = pEnvelope.Id
|
||||
oCommand.Parameters.Add(New SqlParameter("@BYTE_DATA", DirectCast(pDocument.Byte_Data, Object)))
|
||||
|
||||
If Database.ExecuteNonQuery(oCommand, pTransaction) Then
|
||||
pDocument.EnvelopeId = pEnvelope.Id
|
||||
|
||||
@@ -12,8 +12,8 @@ Public Class EmailModel
|
||||
Public Function Insert(pEmail As EmailData) As Boolean
|
||||
Try
|
||||
Dim oSql = "INSERT INTO [dbo].[TBEMLP_EMAIL_OUT] "
|
||||
oSql += " (EMAIL_ADRESS, EMAIL_SUBJ, EMAIL_BODY, ADDED_WHO, SENDING_PROFILE, REFERENCE_ID, REFERENCE_STRING, REMINDER_TYPE_ID, EMAIL_ATTMT1, WF_ID) "
|
||||
oSql += " VALUES (@EMAIL_ADRESS, @EMAIL_SUBJ, @EMAIL_BODY, @ADDED_WHO, @SENDING_PROFILE, @REFERENCE_ID, @REFERENCE_STRING, @REMINDER_TYPE_ID, @EMAIL_ATTMT1, @WF_ID)"
|
||||
oSql += " (EMAIL_ADRESS, EMAIL_SUBJ, EMAIL_BODY, ADDED_WHO, SENDING_PROFILE, REFERENCE_ID, REFERENCE_STRING, REMINDER_TYPE_ID, WF_ID,ATT1_RELATED_ID,ATT1_REL_TYPE) "
|
||||
oSql += " VALUES (@EMAIL_ADRESS, @EMAIL_SUBJ, @EMAIL_BODY, @ADDED_WHO, @SENDING_PROFILE, @REFERENCE_ID, @REFERENCE_STRING, @REMINDER_TYPE_ID, @WF_ID,@ATT1_RELATED_ID,@ATT1_REL_TYPE)"
|
||||
Dim oCommand As New SqlCommand(oSql)
|
||||
oCommand.Parameters.Add("EMAIL_ADRESS", SqlDbType.NVarChar).Value = pEmail.EmailAdress
|
||||
oCommand.Parameters.Add("EMAIL_SUBJ", SqlDbType.NVarChar).Value = pEmail.EmailSubject
|
||||
@@ -23,8 +23,10 @@ Public Class EmailModel
|
||||
oCommand.Parameters.Add("REFERENCE_ID", SqlDbType.Int).Value = pEmail.ReferenceID
|
||||
oCommand.Parameters.Add("REFERENCE_STRING", SqlDbType.NVarChar).Value = pEmail.ReferenceString
|
||||
oCommand.Parameters.Add("REMINDER_TYPE_ID", SqlDbType.Int).Value = 202377
|
||||
oCommand.Parameters.Add("EMAIL_ATTMT1", SqlDbType.NVarChar).Value = pEmail.EmailAttachment
|
||||
'oCommand.Parameters.Add("EMAIL_ATTMT1", SqlDbType.NVarChar).Value = pEmail.EmailAttachment
|
||||
oCommand.Parameters.Add("WF_ID", SqlDbType.Int).Value = pEmail.EmailType ' Wegen DB-Trigger MUSS dieser Wert gesetzt werden
|
||||
oCommand.Parameters.Add("ATT1_RELATED_ID", SqlDbType.Int).Value = pEmail.ATT1_RELATED_ID
|
||||
oCommand.Parameters.Add("ATT1_REL_TYPE", SqlDbType.NVarChar).Value = pEmail.ATT1_REL_TYPE
|
||||
|
||||
If Database.ExecuteNonQuery(oCommand) Then
|
||||
Return True
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Imports System.Web.UI.WebControls
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports EnvelopeGenerator.Common.Constants
|
||||
|
||||
Public Class EnvelopeModel
|
||||
Inherits BaseModel
|
||||
@@ -34,7 +35,7 @@ Public Class EnvelopeModel
|
||||
.Language = pRow.ItemEx("LANGUAGE", "de-DE"),
|
||||
.Status = ObjectEx.ToEnum(Of Constants.EnvelopeStatus)(pRow.ItemEx("STATUS", Constants.EnvelopeStatus.EnvelopeCreated.ToString())),
|
||||
.AddedWhen = pRow.Item("ADDED_WHEN"),
|
||||
.CertificationType = ObjectEx.ToEnum(Of Constants.CertificationType)(pRow.ItemEx("CERTIFICATION_TYPE", Constants.CertificationType.ElectronicSignature.ToString())),
|
||||
.CertificationType = ObjectEx.ToEnum(Of Constants.CertificationType)(pRow.ItemEx("CERTIFICATION_TYPE", Constants.CertificationType.AdvancedElectronicSignature.ToString())),
|
||||
.User = New User(),
|
||||
.ExpiresWhen = pRow.ItemEx(Of Date)("EXPIRES_WHEN", Nothing),
|
||||
.ExpiresWarningWhen = pRow.ItemEx(Of Date)("EXPIRES_WARNING_WHEN", Nothing),
|
||||
@@ -45,9 +46,18 @@ Public Class EnvelopeModel
|
||||
.ReminderIntervalDays = pRow.ItemEx("REMINDER_INTERVAL_DAYS", 0),
|
||||
.UseAccessCode = pRow.ItemEx("USE_ACCESS_CODE", False),
|
||||
.FinalEmailToCreator = ObjectEx.ToEnum(Of Constants.FinalEmailType)(pRow.ItemEx("FINAL_EMAIL_TO_CREATOR", Constants.FinalEmailType.No.ToString())),
|
||||
.FinalEmailToReceivers = ObjectEx.ToEnum(Of Constants.FinalEmailType)(pRow.ItemEx("FINAL_EMAIL_TO_RECEIVERS", Constants.FinalEmailType.No.ToString()))
|
||||
.FinalEmailToReceivers = ObjectEx.ToEnum(Of Constants.FinalEmailType)(pRow.ItemEx("FINAL_EMAIL_TO_RECEIVERS", Constants.FinalEmailType.No.ToString())),
|
||||
.TFA_Enabled = pRow.ItemEx("TFA_Enabled", False)
|
||||
}
|
||||
|
||||
Dim oDOC_RESULT = pRow.Item("DOC_RESULT")
|
||||
If Not IsDBNull(oDOC_RESULT) Then
|
||||
Dim oByte As Byte() = DirectCast(pRow.Item("DOC_RESULT"), Byte())
|
||||
If Not IsNothing(oByte) Then
|
||||
oEnvelope.DOC_RESULT = oByte
|
||||
End If
|
||||
Else
|
||||
oEnvelope.DOC_RESULT = Nothing
|
||||
End If
|
||||
oEnvelope.User = UserModel.SelectUser(oEnvelope.UserId)
|
||||
oEnvelope.Receivers = ReceiverModel.ListEnvelopeReceivers(oEnvelope.Id)
|
||||
oEnvelope.Documents = DocumentModel.List(oEnvelope.Id)
|
||||
@@ -134,13 +144,17 @@ Public Class EnvelopeModel
|
||||
|
||||
Public Function Insert(pEnvelope As Envelope) As Boolean
|
||||
Try
|
||||
Dim oSql = "INSERT INTO [dbo].[TBSIG_ENVELOPE] (MESSAGE, ENVELOPE_UUID, STATUS, USER_ID) "
|
||||
oSql += " VALUES (@MESSAGE, @UUID, @STATUS, @USER_ID)"
|
||||
Dim oSql = $"INSERT INTO [dbo].[TBSIG_ENVELOPE] (MESSAGE, ENVELOPE_UUID, STATUS, USER_ID)
|
||||
VALUES('',
|
||||
'{pEnvelope.Uuid}',
|
||||
'{CInt([Enum].Parse(GetType(EnvelopeStatus), Constants.EnvelopeStatus.EnvelopeCreated))}',
|
||||
'{pEnvelope.UserId}')"
|
||||
Dim oCommand As New SqlCommand(oSql)
|
||||
oCommand.Parameters.Add("MESSAGE", SqlDbType.NVarChar).Value = String.Empty
|
||||
oCommand.Parameters.Add("UUID", SqlDbType.NVarChar).Value = pEnvelope.Uuid
|
||||
oCommand.Parameters.Add("STATUS", SqlDbType.Int).Value = Constants.EnvelopeStatus.EnvelopeCreated
|
||||
oCommand.Parameters.Add("USER_ID", SqlDbType.Int).Value = pEnvelope.UserId
|
||||
'oCommand.Parameters.Add("MESSAGE", SqlDbType.NVarChar).Value = String.Empty
|
||||
'oCommand.Parameters.Add("UUID", SqlDbType.NVarChar).Value = pEnvelope.Uuid
|
||||
'oCommand.Parameters.Add("STATUS", SqlDbType.Int).Value = Constants.EnvelopeStatus.EnvelopeCreated
|
||||
'oCommand.Parameters.Add("USER_ID", SqlDbType.Int).Value = pEnvelope.UserId
|
||||
|
||||
|
||||
If Database.ExecuteNonQuery(oCommand) Then
|
||||
pEnvelope.Id = GetEnvelopeId(pEnvelope)
|
||||
@@ -174,9 +188,11 @@ Public Class EnvelopeModel
|
||||
oSql += " [REMINDER_INTERVAL_DAYS] = @REMINDER_INTERVAL_DAYS, "
|
||||
oSql += " [SEND_REMINDER_EMAILS] = @SEND_REMINDER_EMAILS, "
|
||||
oSql += " [USE_ACCESS_CODE] = @USE_ACCESS_CODE, "
|
||||
oSql += " [CHANGED_WHEN] = GETDATE() "
|
||||
oSql += " [CHANGED_WHEN] = GETDATE(), "
|
||||
oSql += " [TFA_Enabled] = @TFA_Enabled"
|
||||
oSql += " WHERE GUID = @ID AND USER_ID = @USER_ID"
|
||||
|
||||
|
||||
Dim oCommand As New SqlCommand(oSql)
|
||||
oCommand.Parameters.Add("ID", SqlDbType.Int).Value = pEnvelope.Id
|
||||
oCommand.Parameters.Add("USER_ID", SqlDbType.Int).Value = pEnvelope.UserId
|
||||
@@ -185,6 +201,9 @@ Public Class EnvelopeModel
|
||||
oCommand.Parameters.Add("TITLE", SqlDbType.NVarChar).Value = pEnvelope.Title
|
||||
oCommand.Parameters.Add("ENVELOPE_TYPE", SqlDbType.Int).Value = pEnvelope.EnvelopeTypeId
|
||||
oCommand.Parameters.Add("CONTRACT_TYPE", SqlDbType.Int).Value = pEnvelope.ContractType
|
||||
If IsNothing(pEnvelope.Language) Then
|
||||
pEnvelope.Language = "de-DE"
|
||||
End If
|
||||
oCommand.Parameters.Add("LANGUAGE", SqlDbType.NVarChar).Value = pEnvelope.Language
|
||||
oCommand.Parameters.Add("CERTIFICATION_TYPE", SqlDbType.Int).Value = pEnvelope.CertificationType
|
||||
oCommand.Parameters.Add("EXPIRES_WHEN_DAYS", SqlDbType.Int).Value = pEnvelope.ExpiresWhenDays
|
||||
@@ -195,7 +214,7 @@ Public Class EnvelopeModel
|
||||
oCommand.Parameters.Add("REMINDER_INTERVAL_DAYS", SqlDbType.Int).Value = pEnvelope.ReminderIntervalDays
|
||||
oCommand.Parameters.Add("SEND_REMINDER_EMAILS", SqlDbType.Bit).Value = pEnvelope.SendReminderEmails
|
||||
oCommand.Parameters.Add("USE_ACCESS_CODE", SqlDbType.Bit).Value = pEnvelope.UseAccessCode
|
||||
|
||||
oCommand.Parameters.Add("TFA_ENABLED", SqlDbType.Bit).Value = pEnvelope.TFA_Enabled
|
||||
Return Database.ExecuteNonQuery(oCommand, pTransaction)
|
||||
|
||||
Catch ex As Exception
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports EnvelopeGenerator.Common.Constants
|
||||
|
||||
Public Class EnvelopeTypeModel
|
||||
Inherits BaseModel
|
||||
@@ -21,7 +22,8 @@ Public Class EnvelopeTypeModel
|
||||
.FinalEmailToCreator = pRow.ItemEx("FINAL_EMAIL_TO_CREATOR", 0),
|
||||
.FinalEmailToReceivers = pRow.ItemEx("FINAL_EMAIL_TO_RECEIVERS", 0),
|
||||
.ContractType = pRow.ItemEx("CONTRACT_TYPE", 0),
|
||||
.CertificationType = pRow.ItemEx("CERTIFICATION_TYPE", 0)
|
||||
.CertificationType = pRow.ItemEx("CERTIFICATION_TYPE", 0),
|
||||
.TFA_Enabled = pRow.ItemEx("TFA_Enabled", 0)
|
||||
}
|
||||
End Function
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Public Class HistoryModel
|
||||
|
||||
Private Function ToEnvelopeHistoryEntry(pRow As DataRow) As EnvelopeHistoryEntry
|
||||
Return New EnvelopeHistoryEntry() With {
|
||||
.ActionDate = pRow.Item("ACTION_DATE"),
|
||||
.ActionDate = pRow.ItemEx(Of Date)("ACTION_DATE", Nothing),
|
||||
.EnvelopeId = pRow.Item("ENVELOPE_ID"),
|
||||
.Status = pRow.Item("STATUS"),
|
||||
.UserReference = pRow.ItemEx("USER_REFERENCE", "")
|
||||
@@ -18,7 +18,7 @@ Public Class HistoryModel
|
||||
End Function
|
||||
|
||||
Public Function List(pEnvelopeId As Integer) As List(Of EnvelopeHistoryEntry)
|
||||
Dim oSql = $"SELECT * FROM TBSIG_ENVELOPE_HISTORY WHERE ENVELOPE_ID = {pEnvelopeId} ORDER BY GUID DESC"
|
||||
Dim oSql = $"SELECT * FROM TBSIG_ENVELOPE_HISTORY WHERE ENVELOPE_ID = {pEnvelopeId} AND ACTION_DATE IS NOT NULL ORDER BY GUID DESC"
|
||||
Dim oTable = Database.GetDatatable(oSql)
|
||||
Return oTable?.Rows.
|
||||
Cast(Of DataRow).
|
||||
|
||||
@@ -33,7 +33,8 @@ Public Class ReceiverModel
|
||||
.Status = ReceiverSignedStatus,
|
||||
.ColorType = DirectCast(pColorIndex + 1, ColorType),
|
||||
.AccessCode = pRow.ItemEx("ACCESS_CODE", ""),
|
||||
.SignedDate = SignedDate
|
||||
.SignedDate = SignedDate,
|
||||
.PhoneNumber = pRow.ItemEx("PHONE_NUMBER", "")
|
||||
}
|
||||
End Function
|
||||
|
||||
@@ -56,25 +57,29 @@ Public Class ReceiverModel
|
||||
|
||||
Public Function Insert(pReceiver As EnvelopeReceiver, pTransaction As SqlTransaction) As Boolean
|
||||
Try
|
||||
Dim oSql As String = "INSERT INTO [dbo].[TBSIG_RECEIVER]
|
||||
Dim oCheck = $"SELECT COUNT(GUID) FROM [dbo].[TBSIG_RECEIVER] WHERE SIGNATURE = '{pReceiver.GetSignature()}'"
|
||||
Dim oExists = Database.GetScalarValue(oCheck)
|
||||
|
||||
If oExists = 0 Then
|
||||
Dim oSql As String = $"INSERT INTO [dbo].[TBSIG_RECEIVER]
|
||||
([EMAIL_ADDRESS]
|
||||
,[SIGNATURE])
|
||||
VALUES
|
||||
(@EMAIL
|
||||
,@SIGNATURE)"
|
||||
('{pReceiver.Email}'
|
||||
,'{pReceiver.GetSignature()}')"
|
||||
|
||||
Dim oCommand = New SqlCommand(oSql)
|
||||
oCommand.Parameters.Add("EMAIL", SqlDbType.NVarChar).Value = pReceiver.Email
|
||||
oCommand.Parameters.Add("SIGNATURE", SqlDbType.NVarChar).Value = pReceiver.GetSignature()
|
||||
|
||||
Dim oResult = Database.ExecuteNonQuery(oCommand)
|
||||
If oResult = True Then
|
||||
pReceiver.Id = GetReceiverIdByEmail(pReceiver.Email, pTransaction)
|
||||
Dim oCommand = New SqlCommand(oSql)
|
||||
Dim oResult = Database.ExecuteNonQuery(oCommand)
|
||||
If oResult = True Then
|
||||
pReceiver.Id = GetReceiverIdByEmail(pReceiver.Email, pTransaction)
|
||||
Return True
|
||||
Else
|
||||
Return False
|
||||
End If
|
||||
Else
|
||||
Return False
|
||||
Logger.Warn($"Receiver [{pReceiver.Email}] already existing! Check collecting not existing Receivers!")
|
||||
Return True
|
||||
End If
|
||||
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Return False
|
||||
@@ -83,18 +88,18 @@ Public Class ReceiverModel
|
||||
|
||||
Public Function Update(pReceiver As EnvelopeReceiver, pTransaction As SqlTransaction) As Boolean
|
||||
Try
|
||||
Dim oSql As String = "UPDATE [dbo].[TBSIG_USER_RECEIVER]
|
||||
SET [NAME] = @NAME
|
||||
,[COMPANY_NAME] = @COMPANY
|
||||
,[JOB_TITLE] = @JOB
|
||||
WHERE RECEIVER_ID = @RECEIVER_ID"
|
||||
Dim oSql As String = $"UPDATE [dbo].[TBSIG_USER_RECEIVER]
|
||||
SET [NAME] = '{pReceiver.Name}'
|
||||
,[COMPANY_NAME] = '{pReceiver.Company}'
|
||||
,[JOB_TITLE] = '{pReceiver.JobTitle}'
|
||||
WHERE RECEIVER_ID = {pReceiver.Id}"
|
||||
|
||||
Dim oCommand = New SqlCommand(oSql)
|
||||
oCommand.Parameters.Add("NAME", SqlDbType.NVarChar).Value = pReceiver.Name
|
||||
oCommand.Parameters.Add("COMPANY", SqlDbType.NVarChar).Value = pReceiver.Company
|
||||
oCommand.Parameters.Add("JOB", SqlDbType.NVarChar).Value = pReceiver.JobTitle
|
||||
oCommand.Parameters.Add("RECEIVER_ID", SqlDbType.Int).Value = pReceiver.Id
|
||||
oCommand.Parameters.Add("USER_ID", SqlDbType.Int).Value = pReceiver.Id
|
||||
'oCommand.Parameters.Add("NAME", SqlDbType.NVarChar).Value = pReceiver.Name
|
||||
'oCommand.Parameters.Add("COMPANY", SqlDbType.NVarChar).Value = pReceiver.Company
|
||||
'oCommand.Parameters.Add("JOB", SqlDbType.NVarChar).Value = pReceiver.JobTitle
|
||||
'oCommand.Parameters.Add("RECEIVER_ID", SqlDbType.Int).Value = pReceiver.Id
|
||||
'oCommand.Parameters.Add("USER_ID", SqlDbType.Int).Value = pReceiver.Id
|
||||
|
||||
Return Database.ExecuteNonQuery(oCommand, pTransaction)
|
||||
Catch ex As Exception
|
||||
@@ -113,7 +118,7 @@ Public Class ReceiverModel
|
||||
End Function
|
||||
|
||||
Public Function Assign(pEnvelope As Envelope, pReceiver As EnvelopeReceiver, pTransaction As SqlTransaction) As Boolean
|
||||
Dim oSql = "INSERT INTO [dbo].[TBSIG_ENVELOPE_RECEIVER]
|
||||
Dim oSql = $"INSERT INTO [dbo].[TBSIG_ENVELOPE_RECEIVER]
|
||||
([ENVELOPE_ID]
|
||||
,[RECEIVER_ID]
|
||||
,[PRIVATE_MESSAGE]
|
||||
@@ -121,26 +126,28 @@ Public Class ReceiverModel
|
||||
,[NAME]
|
||||
,[JOB_TITLE]
|
||||
,[COMPANY_NAME]
|
||||
,[SEQUENCE])
|
||||
,[SEQUENCE]
|
||||
,[PHONE_NUMBER])
|
||||
VALUES
|
||||
(@ENVELOPE_ID
|
||||
,@RECEIVER_ID
|
||||
,@MESSAGE
|
||||
,@ACCESS_CODE
|
||||
,@NAME
|
||||
,@JOB
|
||||
,@COMPANY
|
||||
,@SEQUENCE)"
|
||||
('{pEnvelope.Id}'
|
||||
,'{pReceiver.Id}'
|
||||
,'{pReceiver.PrivateMessage}'
|
||||
,'{pReceiver.AccessCode}'
|
||||
,'{pReceiver.Name}'
|
||||
,'{pReceiver.JobTitle}'
|
||||
,'{pReceiver.Company}'
|
||||
,'{pReceiver.Sequence}'
|
||||
,'{pReceiver.PhoneNumber}')"
|
||||
|
||||
Dim oCommand As New SqlCommand(oSql)
|
||||
oCommand.Parameters.Add("ENVELOPE_ID", SqlDbType.NVarChar).Value = pEnvelope.Id
|
||||
oCommand.Parameters.Add("RECEIVER_ID", SqlDbType.NVarChar).Value = pReceiver.Id
|
||||
oCommand.Parameters.Add("MESSAGE", SqlDbType.NVarChar).Value = pReceiver.PrivateMessage
|
||||
oCommand.Parameters.Add("ACCESS_CODE", SqlDbType.NVarChar).Value = pReceiver.AccessCode
|
||||
oCommand.Parameters.Add("NAME", SqlDbType.NVarChar).Value = pReceiver.Name
|
||||
oCommand.Parameters.Add("JOB", SqlDbType.NVarChar).Value = pReceiver.JobTitle
|
||||
oCommand.Parameters.Add("COMPANY", SqlDbType.NVarChar).Value = pReceiver.Company
|
||||
oCommand.Parameters.Add("SEQUENCE", SqlDbType.NVarChar).Value = pReceiver.Sequence
|
||||
'oCommand.Parameters.Add("ENVELOPE_ID", SqlDbType.NVarChar).Value = pEnvelope.Id
|
||||
'oCommand.Parameters.Add("RECEIVER_ID", SqlDbType.NVarChar).Value = pReceiver.Id
|
||||
'oCommand.Parameters.Add("MESSAGE", SqlDbType.NVarChar).Value = pReceiver.PrivateMessage
|
||||
'oCommand.Parameters.Add("ACCESS_CODE", SqlDbType.NVarChar).Value = pReceiver.AccessCode
|
||||
'oCommand.Parameters.Add("NAME", SqlDbType.NVarChar).Value = pReceiver.Name
|
||||
'oCommand.Parameters.Add("JOB", SqlDbType.NVarChar).Value = pReceiver.JobTitle
|
||||
'oCommand.Parameters.Add("COMPANY", SqlDbType.NVarChar).Value = pReceiver.Company
|
||||
'oCommand.Parameters.Add("SEQUENCE", SqlDbType.NVarChar).Value = pReceiver.Sequence
|
||||
|
||||
Return Database.ExecuteNonQuery(oCommand, pTransaction)
|
||||
End Function
|
||||
@@ -266,6 +273,22 @@ Public Class ReceiverModel
|
||||
Return String.Empty
|
||||
End Try
|
||||
End Function
|
||||
Public Function GetLastUsedReceiverPhone(pEmailAddress As String, pUserId As Integer) As String
|
||||
Try
|
||||
Dim oSql As String
|
||||
oSql = "SELECT TOP 1 [PHONE_NUMBER] FROM dbo.VWSIG_ENVELOPE_RECEIVERS "
|
||||
oSql += $" WHERE ENV_USERID_CREATED = {pUserId}) "
|
||||
oSql += $" AND EMAIL_ADDRESS = '{pEmailAddress}' "
|
||||
oSql += " AND Len([PHONE_NUMBER]) > 0 "
|
||||
oSql += " ORDER BY [ADDED_WHEN] DESC"
|
||||
|
||||
Return Database.GetScalarValue(oSql)
|
||||
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Return String.Empty
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private Function GetReceiverIdByEmail(pEmailAddress As String, pTransaction As SqlTransaction) As Integer
|
||||
Try
|
||||
|
||||
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
|
||||
' indem Sie "*" wie unten gezeigt eingeben:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("1.3.6.0")>
|
||||
<Assembly: AssemblyFileVersion("1.3.6.0")>
|
||||
<Assembly: AssemblyVersion("2.2.0.0")>
|
||||
<Assembly: AssemblyFileVersion("2.2.0.0")>
|
||||
|
||||
@@ -15,7 +15,7 @@ Option Explicit On
|
||||
Namespace My
|
||||
|
||||
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0"), _
|
||||
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0"), _
|
||||
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Partial Friend NotInheritable Class MySettings
|
||||
Inherits Global.System.Configuration.ApplicationSettingsBase
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Profiles />
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
</SettingsFile>
|
||||
@@ -1,5 +1,6 @@
|
||||
Imports DevExpress.DataAccess.Native.Web
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports EnvelopeGenerator.Common.My.Resources
|
||||
|
||||
Public Class ActionService
|
||||
Inherits BaseService
|
||||
@@ -33,14 +34,28 @@ Public Class ActionService
|
||||
|
||||
Return True
|
||||
End Function
|
||||
Public Function Resend_Receiver(pEnvelope As Envelope, pmail As String) As Boolean
|
||||
If HistoryService.SetEnvelopeStatus(pEnvelope, Constants.EnvelopeStatus.EnvelopeQueued, pEnvelope.User.Email) = False Then
|
||||
Return False
|
||||
End If
|
||||
Dim oSendResult As Boolean = False
|
||||
For Each oReceiver In pEnvelope.Receivers
|
||||
EmailService.SendDocumentReceivedEmail(pEnvelope, oReceiver)
|
||||
Next
|
||||
Return oSendResult
|
||||
End Function
|
||||
Public Function ResendReceiver(pEnvelope As Envelope, pReceiver As EnvelopeReceiver) As Boolean
|
||||
Return EmailService.SendDocumentReceivedEmail(pEnvelope, pReceiver)
|
||||
End Function
|
||||
|
||||
Public Function DeleteEnvelope(pEnvelope As Envelope) As Boolean
|
||||
|
||||
Public Function DeleteEnvelope(pEnvelope As Envelope, pReason As String) As Boolean
|
||||
If HistoryService.SetEnvelopeStatus(pEnvelope, Constants.EnvelopeStatus.EnvelopeDeleted, pEnvelope.User.Email) = False Then
|
||||
Return False
|
||||
End If
|
||||
|
||||
Dim oSendResult = pEnvelope.Receivers.
|
||||
Select(Function(r) EmailService.SendEnvelopeDeletedEmail(pEnvelope, r)).
|
||||
Select(Function(r) EmailService.SendEnvelopeDeletedEmail(pEnvelope, r, pReason)).
|
||||
All(Function(r) r = True)
|
||||
|
||||
If oSendResult = False Then
|
||||
@@ -108,20 +123,20 @@ Public Class ActionService
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Public Function CompleteEnvelope(pEnvelope As Envelope, pReceiver As EnvelopeReceiver, pAttachment As String) As Boolean
|
||||
Public Function CompleteEnvelope(pEnvelope As Envelope, pReceiver As EnvelopeReceiver) As Boolean ', pAttachment As String
|
||||
If HistoryService.SetEnvelopeStatus(pEnvelope, Constants.EnvelopeStatus.MessageCompletionSent, pReceiver.Email) = False Then
|
||||
Return False
|
||||
End If
|
||||
|
||||
Return EmailService.SendDocumentCompletedEmailToReceiver(pEnvelope, pReceiver, pAttachment)
|
||||
Return EmailService.SendDocumentCompletedEmailToReceiver(pEnvelope, pReceiver) ', pAttachment
|
||||
End Function
|
||||
|
||||
Public Function CompleteEnvelope(pEnvelope As Envelope, pAttachment As String) As Boolean
|
||||
Public Function CompleteEnvelope(pEnvelope As Envelope) As Boolean ', pAttachment As String
|
||||
If HistoryService.SetEnvelopeStatus(pEnvelope, Constants.EnvelopeStatus.MessageCompletionSent, pEnvelope.User.Email) = False Then
|
||||
Return False
|
||||
End If
|
||||
|
||||
Return EmailService.SendDocumentCompletedEmailToCreator(pEnvelope, pAttachment)
|
||||
Return EmailService.SendDocumentCompletedEmailToCreator(pEnvelope) ', pAttachment
|
||||
End Function
|
||||
|
||||
Public Function CreateReport(pEnvelope As Envelope) As Boolean
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports EnvelopeGenerator.Common.My.Resources
|
||||
|
||||
Public Class EmailService
|
||||
Inherits BaseService
|
||||
@@ -15,14 +16,14 @@ Public Class EmailService
|
||||
EmailTemplate = New TemplateService(pState)
|
||||
End Sub
|
||||
|
||||
Public Function SendEnvelopeDeletedEmail(pEnvelope As Envelope, pReceiver As EnvelopeReceiver) As Boolean
|
||||
Public Function SendEnvelopeDeletedEmail(pEnvelope As Envelope, pReceiver As EnvelopeReceiver, pReason As String) As Boolean
|
||||
Logger.Debug("Creating email data object.")
|
||||
Dim oEmailData As New EmailData(pEnvelope, pReceiver, Constants.EnvelopeStatus.MessageDeletionSent) With
|
||||
{
|
||||
.SignatureLink = ""
|
||||
}
|
||||
|
||||
EmailTemplate.FillEnvelopeDeletedEmailBody(oEmailData)
|
||||
EmailTemplate.FillEnvelopeDeletedEmailBody(oEmailData, pReason)
|
||||
|
||||
If EmailModel.Insert(oEmailData) = False Then
|
||||
Logger.Error("EMail data could not be inserted.")
|
||||
@@ -49,6 +50,15 @@ Public Class EmailService
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Public Function GetReceiverUrl(pEnvelope As Envelope, pReceiver As EnvelopeReceiver) As String
|
||||
Dim oEmailData As New EmailData(pEnvelope, pReceiver, Constants.EnvelopeStatus.MessageInvitationSent) With
|
||||
{
|
||||
.SignatureLink = Helpers.GetEnvelopeURL(State.DbConfig.SignatureHost, pEnvelope.Uuid, pReceiver.Signature)
|
||||
}
|
||||
Return oEmailData.SignatureLink
|
||||
End Function
|
||||
|
||||
|
||||
Public Function SendDocumentAccessCodeReceivedEmail(pEnvelope As Envelope, pReceiver As EnvelopeReceiver) As Boolean
|
||||
Logger.Debug("Creating email data object.")
|
||||
Dim oEmailData As New EmailData(pEnvelope, pReceiver, Constants.EnvelopeStatus.MessageAccessCodeSent) With
|
||||
@@ -83,14 +93,15 @@ Public Class EmailService
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Public Function SendDocumentCompletedEmailToReceiver(pEnvelope As Envelope, pReceiver As EnvelopeReceiver, pAttachment As String) As Boolean
|
||||
Public Function SendDocumentCompletedEmailToReceiver(pEnvelope As Envelope, pReceiver As EnvelopeReceiver) As Boolean ', pAttachment As String
|
||||
Logger.Debug("Creating email data object.")
|
||||
Dim oEmailData = New EmailData(pEnvelope, pReceiver, Constants.EnvelopeStatus.MessageCompletionSent) With
|
||||
{
|
||||
.SignatureLink = "",
|
||||
.EmailAttachment = pAttachment
|
||||
.ATT1_RELATED_ID = pEnvelope.Id,
|
||||
.ATT1_REL_TYPE = "EnvelopeResult"
|
||||
}
|
||||
|
||||
' .EmailAttachment = pAttachment,
|
||||
Logger.Debug("Sending mail to receiver: [{0}]", oEmailData.EmailAdress)
|
||||
|
||||
EmailTemplate.FillDocumentCompletedEmailBody(oEmailData)
|
||||
@@ -103,14 +114,15 @@ Public Class EmailService
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Public Function SendDocumentCompletedEmailToCreator(pEnvelope As Envelope, pAttachment As String) As Boolean
|
||||
Public Function SendDocumentCompletedEmailToCreator(pEnvelope As Envelope) As Boolean ', pAttachment As String
|
||||
Logger.Debug("Creating email data object.")
|
||||
Dim oEmailData = New EmailData(pEnvelope, Constants.EnvelopeStatus.MessageCompletionSent) With
|
||||
{
|
||||
.SignatureLink = "",
|
||||
.EmailAttachment = pAttachment
|
||||
.ATT1_RELATED_ID = pEnvelope.Id,
|
||||
.ATT1_REL_TYPE = "EnvelopeResult"
|
||||
}
|
||||
|
||||
'.EmailAttachment = pAttachment,
|
||||
EmailTemplate.FillDocumentCompletedEmailBody(oEmailData)
|
||||
|
||||
If EmailModel.Insert(oEmailData) = False Then
|
||||
|
||||
@@ -16,7 +16,7 @@ Public Class TemplateService
|
||||
EmailHtmlTemplateModel = New EmailTemplateModel(pState)
|
||||
End Sub
|
||||
|
||||
Private Sub InitDictionary(pEmailData As EmailData)
|
||||
Private Sub InitDictionary(pEmailData As EmailData, Optional pReason As String = "")
|
||||
Logger.Debug("Initializing dictionary..")
|
||||
|
||||
_replaceDictionary = New Dictionary(Of String, String) From {
|
||||
@@ -28,7 +28,8 @@ Public Class TemplateService
|
||||
{"[LINK_TO_DOCUMENT_TEXT]", $"{pEmailData.SignatureLink.Truncate(40)}.."},
|
||||
{"[DOCUMENT_TITLE]", pEmailData.EnvelopeTitle},
|
||||
{"[MESSAGE]", pEmailData.Message},
|
||||
{"[DOCUMENT_ACCESS_CODE]", pEmailData.ReceiverAccessCode}
|
||||
{"[DOCUMENT_ACCESS_CODE]", pEmailData.ReceiverAccessCode},
|
||||
{"[REASON]", pReason}
|
||||
}
|
||||
End Sub
|
||||
|
||||
@@ -40,11 +41,11 @@ Public Class TemplateService
|
||||
pEmailData.EmailSubject = FillTemplate(oTemplate.Subject)
|
||||
End Sub
|
||||
|
||||
Public Sub FillEnvelopeDeletedEmailBody(pEmailData As EmailData)
|
||||
InitDictionary(pEmailData)
|
||||
Public Sub FillEnvelopeDeletedEmailBody(pEmailData As EmailData, pReason As String)
|
||||
InitDictionary(pEmailData, pReason)
|
||||
Dim oTemplate = EmailHtmlTemplateModel.GetById(Constants.EmailTemplateType.DocumentDeleted)
|
||||
|
||||
pEmailData.EmailBody = FillTemplate(oTemplate.Body)
|
||||
pEmailData.EmailBody = FillTemplate(oTemplate.Body, pReason)
|
||||
pEmailData.EmailSubject = FillTemplate(oTemplate.Subject)
|
||||
End Sub
|
||||
|
||||
@@ -72,11 +73,12 @@ Public Class TemplateService
|
||||
pEmailData.EmailSubject = FillTemplate(oTemplate.Subject)
|
||||
End Sub
|
||||
|
||||
Private Function FillTemplate(pTemplate As String) As String
|
||||
Private Function FillTemplate(pTemplate As String, Optional pReason As String = "") As String
|
||||
Dim oText As String = pTemplate
|
||||
|
||||
For Each dictItem As KeyValuePair(Of String, String) In _replaceDictionary
|
||||
If oText.Contains(dictItem.Key) Then
|
||||
|
||||
oText = oText.Replace(dictItem.Key, dictItem.Value)
|
||||
|
||||
End If
|
||||
|
||||
@@ -117,6 +117,9 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Dialog Concat PDF" xml:space="preserve">
|
||||
<value>Please select the PDF documents you would like to link/concat:</value>
|
||||
</data>
|
||||
<data name="Do you really want to delete this envelope" xml:space="preserve">
|
||||
<value>Do you really want to delete this envelope?</value>
|
||||
</data>
|
||||
@@ -138,6 +141,15 @@
|
||||
<data name="Document Could Not Be Saved" xml:space="preserve">
|
||||
<value>Document could not be saved!</value>
|
||||
</data>
|
||||
<data name="Document forwarded" xml:space="preserve">
|
||||
<value>Document forwarded to receiver: {0}</value>
|
||||
</data>
|
||||
<data name="Drop only one file" xml:space="preserve">
|
||||
<value>Currently, only one PDF file is permitted via drag and drop.</value>
|
||||
</data>
|
||||
<data name="Drop only pdf" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Edit Envelope" xml:space="preserve">
|
||||
<value>Edit Envelope</value>
|
||||
</data>
|
||||
@@ -154,7 +166,7 @@
|
||||
<value>Envelope could not be sent!</value>
|
||||
</data>
|
||||
<data name="Envelope Invitations Sent" xml:space="preserve">
|
||||
<value>Envelope Invitations Sent</value>
|
||||
<value>The invitations have been scheduled for dispatch.s</value>
|
||||
</data>
|
||||
<data name="Envelope Overview" xml:space="preserve">
|
||||
<value>Overview</value>
|
||||
@@ -165,6 +177,12 @@
|
||||
<data name="Envelope-Editor" xml:space="preserve">
|
||||
<value>Envelope-Editor</value>
|
||||
</data>
|
||||
<data name="Error email Validation" xml:space="preserve">
|
||||
<value>The email [ @Mail ] could not be varified!</value>
|
||||
</data>
|
||||
<data name="Error phone Validation" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Error sending the envelope" xml:space="preserve">
|
||||
<value>Error sending the envelope:</value>
|
||||
</data>
|
||||
@@ -186,6 +204,9 @@
|
||||
<data name="Invalid Email Address" xml:space="preserve">
|
||||
<value>Receiver {0} has an invalid Email Address.</value>
|
||||
</data>
|
||||
<data name="Invitation successfully resend" xml:space="preserve">
|
||||
<value>Invitation to [@Mail] has been send once again!</value>
|
||||
</data>
|
||||
<data name="Missing Documents" xml:space="preserve">
|
||||
<value>Missing Documents</value>
|
||||
</data>
|
||||
|
||||
@@ -117,6 +117,9 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Dialog Concat PDF" xml:space="preserve">
|
||||
<value>Bitte wählen Sie die PDF-Dokumente die Sie verketten möchten:</value>
|
||||
</data>
|
||||
<data name="Do you really want to delete this envelope" xml:space="preserve">
|
||||
<value>Wollen Sie diesen Umschlag wirklich löschen?</value>
|
||||
</data>
|
||||
@@ -138,6 +141,12 @@
|
||||
<data name="Document Could Not Be Saved" xml:space="preserve">
|
||||
<value>Dokument konnte nicht gespeichert werden!</value>
|
||||
</data>
|
||||
<data name="Document forwarded" xml:space="preserve">
|
||||
<value>Umschlag an Empfänger {0} weitergeleitet.</value>
|
||||
</data>
|
||||
<data name="Drop only one file" xml:space="preserve">
|
||||
<value>Aktuell ist per Drag and Drop nur eine PDF-Datei erlaubt.</value>
|
||||
</data>
|
||||
<data name="Edit Envelope" xml:space="preserve">
|
||||
<value>Bearbeite Umschlag</value>
|
||||
</data>
|
||||
@@ -154,7 +163,7 @@
|
||||
<value>Umschlag konnte nicht gesendet werden!</value>
|
||||
</data>
|
||||
<data name="Envelope Invitations Sent" xml:space="preserve">
|
||||
<value>Die Einladungen wurden versendet</value>
|
||||
<value>Die Einladungen zum Signieren wurden zum Versand eingereiht.</value>
|
||||
</data>
|
||||
<data name="Envelope Overview" xml:space="preserve">
|
||||
<value>Übersicht</value>
|
||||
@@ -165,6 +174,13 @@
|
||||
<data name="Envelope-Editor" xml:space="preserve">
|
||||
<value>Umschlag-Editor</value>
|
||||
</data>
|
||||
<data name="Error email Validation" xml:space="preserve">
|
||||
<value>Die Email-Adresse [ @Mail ] konnte nicht validiert werden!</value>
|
||||
</data>
|
||||
<data name="Error phone Validation" xml:space="preserve">
|
||||
<value>The mobile phone number [@PhoneNr] could not be validated.
|
||||
Pattern: +491234567890</value>
|
||||
</data>
|
||||
<data name="Error sending the envelope" xml:space="preserve">
|
||||
<value>Fehler beim Senden des Umschlags:</value>
|
||||
</data>
|
||||
@@ -186,6 +202,9 @@
|
||||
<data name="Invalid Email Address" xml:space="preserve">
|
||||
<value>Empfänger {0} hat keine gültige Email Addresse.</value>
|
||||
</data>
|
||||
<data name="Invitation successfully resend" xml:space="preserve">
|
||||
<value>Die Einladung an [@Mail] wurde nochmal versendet!</value>
|
||||
</data>
|
||||
<data name="Missing Documents" xml:space="preserve">
|
||||
<value>Fehlendes Dokument</value>
|
||||
</data>
|
||||
|
||||
@@ -64,6 +64,15 @@ Namespace My.Resources
|
||||
End Set
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Bitte wählen Sie die PDF-Dokumente die Sie verketten möchten: ähnelt.
|
||||
'''</summary>
|
||||
Public Shared ReadOnly Property Dialog_Concat_PDF() As String
|
||||
Get
|
||||
Return ResourceManager.GetString("Dialog Concat PDF", resourceCulture)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Wollen Sie diesen Umschlag wirklich löschen? ähnelt.
|
||||
'''</summary>
|
||||
@@ -127,6 +136,24 @@ Namespace My.Resources
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Umschlag an Empfänger {0} weitergeleitet. ähnelt.
|
||||
'''</summary>
|
||||
Public Shared ReadOnly Property Document_forwarded() As String
|
||||
Get
|
||||
Return ResourceManager.GetString("Document forwarded", resourceCulture)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Aktuell ist per Drag and Drop nur eine PDF-Datei erlaubt. ähnelt.
|
||||
'''</summary>
|
||||
Public Shared ReadOnly Property Drop_only_one_file() As String
|
||||
Get
|
||||
Return ResourceManager.GetString("Drop only one file", resourceCulture)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Bearbeite Umschlag ähnelt.
|
||||
'''</summary>
|
||||
@@ -182,7 +209,7 @@ Namespace My.Resources
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Die Einladungen wurden versendet ähnelt.
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Die Einladungen zum Signieren wurden zum Versand eingereiht. ähnelt.
|
||||
'''</summary>
|
||||
Public Shared ReadOnly Property Envelope_Invitations_Sent() As String
|
||||
Get
|
||||
@@ -208,6 +235,25 @@ Namespace My.Resources
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Die Email-Adresse [ @Mail ] konnte nicht validiert werden! ähnelt.
|
||||
'''</summary>
|
||||
Public Shared ReadOnly Property Error_email_Validation() As String
|
||||
Get
|
||||
Return ResourceManager.GetString("Error email Validation", resourceCulture)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die The mobile phone number [@PhoneNr] could not be validated.
|
||||
'''Pattern: +491234567890 ähnelt.
|
||||
'''</summary>
|
||||
Public Shared ReadOnly Property Error_phone_Validation() As String
|
||||
Get
|
||||
Return ResourceManager.GetString("Error phone Validation", resourceCulture)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Fehler beim Senden des Umschlags: ähnelt.
|
||||
'''</summary>
|
||||
@@ -271,6 +317,15 @@ Namespace My.Resources
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Die Einladung an [@Mail] wurde nochmal versendet! ähnelt.
|
||||
'''</summary>
|
||||
Public Shared ReadOnly Property Invitation_successfully_resend() As String
|
||||
Get
|
||||
Return ResourceManager.GetString("Invitation successfully resend", resourceCulture)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Fehlendes Dokument ähnelt.
|
||||
'''</summary>
|
||||
|
||||
18
EnvelopeGenerator.Common/Strings/Model.Designer.vb
generated
18
EnvelopeGenerator.Common/Strings/Model.Designer.vb
generated
@@ -91,6 +91,15 @@ Namespace My.Resources
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Fortgeschrittene Elektronische Signatur ähnelt.
|
||||
'''</summary>
|
||||
Public Shared ReadOnly Property AdvancedElectronicSignature() As String
|
||||
Get
|
||||
Return ResourceManager.GetString("AdvancedElectronicSignature", resourceCulture)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Abgeschlossen ähnelt.
|
||||
'''</summary>
|
||||
@@ -154,15 +163,6 @@ Namespace My.Resources
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Elektronische Signatur ähnelt.
|
||||
'''</summary>
|
||||
Public Shared ReadOnly Property ElectronicSignature() As String
|
||||
Get
|
||||
Return ResourceManager.GetString("ElectronicSignature", resourceCulture)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Sucht eine lokalisierte Zeichenfolge, die Archiviert ähnelt.
|
||||
'''</summary>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user