Compare commits
798 Commits
cb44e25fea
...
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 | ||
|
|
6131948f2a | ||
|
|
0a01bf59ef | ||
|
|
a4ed41419d | ||
|
|
6460c2b4ea | ||
|
|
91930c94e9 | ||
|
|
e0bbdf8c0e | ||
|
|
c8106f4fb0 | ||
|
|
9f568e357e | ||
|
|
52ffcc21cc | ||
|
|
32a965800e | ||
|
|
c7dba51ec9 | ||
| 8657c0b212 | |||
| 54debebd05 | |||
| c77772aa7c | |||
|
|
37908b6a1b | ||
|
|
277f5d3f0d | ||
| 2723b10a45 | |||
|
|
b7fbb21076 | ||
|
|
b849a8d87b | ||
|
|
26fe798a68 | ||
|
|
119f54e8aa | ||
|
|
73cb1d8963 | ||
|
|
9b39f0b4ae | ||
|
|
f54532a4b1 | ||
|
|
13b9003186 | ||
|
|
bdf7bdd37a | ||
|
|
0ad1d214ba | ||
|
|
eea1bd2177 | ||
|
|
d8742332ec | ||
|
|
27a611e8dc | ||
|
|
f50a19d537 | ||
|
|
0dfc9b4f09 | ||
|
|
8581cb555a | ||
|
|
97987aa22f | ||
|
|
f8b30e1a06 | ||
|
|
788d7fac9f | ||
|
|
c4e9f5aa2b | ||
|
|
d8ba020bb9 | ||
|
|
fd4dd8b457 | ||
|
|
bc178caec1 | ||
|
|
49e6da3d79 | ||
|
|
feb429f8f8 | ||
|
|
d1fc258f19 | ||
|
|
681583b3f0 | ||
| d47f75133d | |||
| eedd80d1c9 | |||
|
|
330ffe30a5 | ||
|
|
1b85236513 | ||
| 1eba05e5f7 | |||
|
|
aadcef6b15 | ||
|
|
951c9d9122 | ||
| 124414b940 | |||
| db57da0e5c | |||
| 2bf784690d | |||
|
|
dbeabab832 | ||
| b2f6076fb2 | |||
|
|
eb6e1cef03 | ||
|
|
bbfccc4a4f | ||
| cd7af973a1 | |||
|
|
2d49e4704d | ||
|
|
33f5bec8d0 | ||
|
|
1ab7235fcf | ||
|
|
c859a721e6 | ||
|
|
a049166d83 | ||
|
|
5dd4b3496c | ||
| 03f24e6d61 | |||
| faf700eac2 | |||
| 855cbae55e | |||
|
|
08ffecaea7 | ||
|
|
6aef316b03 | ||
| f803fc03de | |||
| 474bf89ee8 | |||
|
|
752dbe3718 | ||
|
|
cd23c5b974 | ||
| 1108fa47e0 | |||
| e20b9c0bb6 | |||
|
|
fe9c5d048f | ||
|
|
c617dbb528 | ||
| e4545a90d4 | |||
| 7c450c56ed | |||
|
|
327102d63a | ||
|
|
588b532d86 | ||
|
|
5b313e069e | ||
|
|
970aa5056f | ||
|
|
7abde3a1f4 | ||
|
|
9c66de2b8e | ||
|
|
f5cb74d9c7 | ||
|
|
cb2e3eb955 | ||
| f42ef8107c | |||
|
|
538b6d4bcd | ||
|
|
70e4842a39 | ||
|
|
c45939b89b | ||
| ba6406b4b5 | |||
|
|
25f7aeb45c | ||
|
|
078b1d30fe | ||
|
|
3675e83102 | ||
| 27e5e9245e | |||
| 364e478b52 | |||
| 3701ac30ef | |||
|
|
2d1574bcbf | ||
| d0b7c6fbd8 | |||
|
|
f506587d2c | ||
|
|
489c7879da | ||
|
|
3b3445cc03 | ||
|
|
f6480adb04 | ||
|
|
7124ad3015 | ||
|
|
6f91ecac83 | ||
|
|
763ac96f4e | ||
|
|
a1062027c8 | ||
|
|
411851b0f6 | ||
|
|
0455795165 | ||
| c2d27e089a | |||
| 0f41312a01 | |||
| c44ade2ee1 | |||
| 9ea63b7cbe | |||
| 6dad6c1e96 | |||
| e143b7bccc | |||
| 78ed65fb9f | |||
|
|
5d210350e7 | ||
| 3d20a9b401 | |||
| 064171e6ca | |||
| 99008dfbe7 | |||
| df02dcf0cf | |||
| 62d88d6770 |
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,21 +1,41 @@
|
||||
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
|
||||
EnvelopeSaved = 1002
|
||||
EnvelopeQueued = 1003
|
||||
EnvelopeSent = 1004
|
||||
EnvelopeSent = 1004 ' Nicht verwendet
|
||||
EnvelopePartlySigned = 1005
|
||||
EnvelopeCompletelySigned = 1006
|
||||
EnvelopeArchived = 1007
|
||||
EnvelopeTransmittedDMS = 1008
|
||||
EnvelopeReportCreated = 1007
|
||||
EnvelopeArchived = 1008
|
||||
EnvelopeDeleted = 1009
|
||||
DocumentOpened = 2001
|
||||
DocumentSigned = 2002
|
||||
SignatureConfirmed = 2003
|
||||
TriggerInvitationSent = 3001 ' Wird von Trigger verwendet
|
||||
AccessCodeRequested = 2001
|
||||
AccessCodeCorrect = 2002
|
||||
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
|
||||
MessageDeletionSent = 3004
|
||||
MessageCompletionSent = 3005
|
||||
End Enum
|
||||
|
||||
'TODO: standardize in xwiki
|
||||
Public Enum ReferenceType
|
||||
Receiver
|
||||
Sender
|
||||
System
|
||||
Unknown
|
||||
End Enum
|
||||
|
||||
Public Enum ElementStatus
|
||||
@@ -55,13 +75,59 @@
|
||||
ReceiverColor9 = 9
|
||||
ReceiverColor10 = 10
|
||||
End Enum
|
||||
|
||||
Public Enum CertificationType
|
||||
AdvancedElectronicSignature = 1
|
||||
'ElectronicSignature = 1
|
||||
'QualifiedSignature = 2
|
||||
End Enum
|
||||
|
||||
Public Enum FinalEmailType
|
||||
No = 0
|
||||
Yes = 1
|
||||
YesWithAttachment = 2
|
||||
End Enum
|
||||
|
||||
Public Enum PageOrientation
|
||||
Portrait = 0
|
||||
Landscape = 1
|
||||
End Enum
|
||||
|
||||
Public Enum EmailTemplateType
|
||||
DocumentReceived
|
||||
DocumentSigned
|
||||
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"
|
||||
|
||||
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
|
||||
|
||||
@@ -1,32 +1,64 @@
|
||||
|
||||
Public Class EmailData
|
||||
Public Property EmailAdress As String
|
||||
Public Property EmailSubject As String
|
||||
Public Property EmailBody As String
|
||||
Public Property ReferenceID As Integer
|
||||
Public Property ReferenceString As String
|
||||
Public Property EmailAdress As String = ""
|
||||
Public Property EmailSubject As String = ""
|
||||
Public Property EmailBody As String = ""
|
||||
Public Property EmailType As Constants.EnvelopeStatus = Constants.EnvelopeStatus.Invalid
|
||||
Public Property ReferenceID As Integer = 0
|
||||
Public Property ReferenceString As String = ""
|
||||
|
||||
Public Property ReceiverAccessCode As String = ""
|
||||
Public Property ReceiverName As String = ""
|
||||
Public Property SenderName As String = ""
|
||||
Public Property SenderAdress As String = ""
|
||||
|
||||
Public Property ReceiverName As String
|
||||
Public Property SenderName As String
|
||||
Public Property SenderAdress As String
|
||||
Public Property SignatureLink As String
|
||||
Public Property Message As String
|
||||
Public Property SignatureLink As String = ""
|
||||
Public Property Message As String = ""
|
||||
Public Property EnvelopeTitle As String = ""
|
||||
|
||||
Public Sub New(pEnvelope As Envelope, pReceiver As EnvelopeReceiver)
|
||||
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
|
||||
''' </summary>
|
||||
''' <param name="pEnvelope"></param>
|
||||
''' <param name="pReceiver"></param>
|
||||
''' <param name="pStatus"></param>
|
||||
Public Sub New(pEnvelope As Envelope, pReceiver As EnvelopeReceiver, pStatus As Constants.EnvelopeStatus)
|
||||
EmailAdress = pReceiver.Email
|
||||
EmailSubject = pEnvelope.Subject
|
||||
EmailSubject = String.Empty
|
||||
EmailType = pStatus
|
||||
|
||||
Message = pEnvelope.Message
|
||||
ReferenceID = pEnvelope.Id
|
||||
ReferenceString = pEnvelope.Uuid
|
||||
ReceiverName = pReceiver.Name
|
||||
ReceiverAccessCode = pReceiver.AccessCode
|
||||
SenderAdress = pEnvelope.User.Email
|
||||
SenderName = pEnvelope.User.FullName
|
||||
EnvelopeTitle = pEnvelope.Title
|
||||
End Sub
|
||||
|
||||
Public Sub New()
|
||||
''' <summary>
|
||||
''' Constructor for sending email to creator
|
||||
''' </summary>
|
||||
''' <param name="pEnvelope"></param>
|
||||
''' <param name="pStatus"></param>
|
||||
Public Sub New(pEnvelope As Envelope, pStatus As Constants.EnvelopeStatus)
|
||||
EmailAdress = pEnvelope.User.Email
|
||||
EmailSubject = String.Empty
|
||||
EmailType = pStatus
|
||||
|
||||
Message = pEnvelope.Message
|
||||
ReferenceID = pEnvelope.Id
|
||||
ReferenceString = pEnvelope.Uuid
|
||||
ReceiverName = pEnvelope.User.FullName
|
||||
ReceiverAccessCode = String.Empty
|
||||
SenderAdress = pEnvelope.User.Email
|
||||
SenderName = pEnvelope.User.FullName
|
||||
EnvelopeTitle = pEnvelope.Title
|
||||
End Sub
|
||||
|
||||
|
||||
|
||||
End Class
|
||||
|
||||
@@ -1,138 +1,8 @@
|
||||
Imports DigitalData.Modules.Base
|
||||
Public Class EmailTemplate
|
||||
|
||||
Public Class EmailTemplate
|
||||
Private _DocumentReceivedBodyTemplate As List(Of String)
|
||||
Private _DocumentSignedBodyTemplate As List(Of String)
|
||||
Private _DocumentCompletedBodyTemplate As List(Of String)
|
||||
Private _DocumentDeletedBodyTemplate As List(Of String)
|
||||
Public Property Id As Integer
|
||||
Public Property Name As String
|
||||
Public Property Body As String
|
||||
Public Property Subject As String
|
||||
|
||||
Private _DocumentReceivedSubjectTemplate As String
|
||||
Private _DocumentSignedSubjectTemplate As String
|
||||
Private _DocumentDeletedSubjectTemplate As String
|
||||
Private _DocumentCompletedSubjectTemplate As String
|
||||
|
||||
Private _replaceDictionary As Dictionary(Of String, String)
|
||||
|
||||
Private DbConfig As DbConfig
|
||||
|
||||
Public Sub New(pState As State)
|
||||
InitBodyTemplates()
|
||||
InitSubjectTemplates()
|
||||
|
||||
DbConfig = pState.DbConfig
|
||||
End Sub
|
||||
|
||||
Private Sub InitSubjectTemplates()
|
||||
_DocumentReceivedSubjectTemplate = "Dokument zur Unterschrift erhalten: '<DOCUMENT_TITLE>'"
|
||||
_DocumentSignedSubjectTemplate = "Dokument unterschrieben: '<DOCUMENT_TITLE>'"
|
||||
_DocumentDeletedSubjectTemplate = "Dokument zurueckgezogen: '<DOCUMENT_TITLE>'"
|
||||
_DocumentCompletedSubjectTemplate = "Dokument abgeschlossen: '<DOCUMENT_TITLE>'"
|
||||
End Sub
|
||||
|
||||
Private Sub InitBodyTemplates()
|
||||
_DocumentReceivedBodyTemplate = New List(Of String) From {
|
||||
"Guten Tag, <NAME_RECEIVER>,",
|
||||
"",
|
||||
"<NAME_SENDER> hat Ihnen ein Dokument zum <SIGNATURE_TYPE> gesendet.",
|
||||
"",
|
||||
"Über den folgenden Link können Sie das Dokument einsehen: <a href=""<LINK_TO_DOCUMENT>""><LINK_TO_DOCUMENT_TEXT></a>",
|
||||
"",
|
||||
"<MESSAGE>",
|
||||
"",
|
||||
"Mit freundlichen Grüßen",
|
||||
"<NAME_PORTAL>"
|
||||
}
|
||||
|
||||
_DocumentSignedBodyTemplate = New List(Of String) From {
|
||||
"Guten Tag, <NAME_RECEIVER>",
|
||||
"",
|
||||
"hiermit bestätigen wir Ihnen die erfolgreiche Signatur für den Vorgang <DOCUMENT_TITLE>.",
|
||||
"",
|
||||
"Mit freundlichen Grüßen",
|
||||
"<NAME_PORTAL>"
|
||||
}
|
||||
|
||||
_DocumentDeletedBodyTemplate = New List(Of String) From {
|
||||
"Guten Tag, <NAME_RECEIVER>",
|
||||
"",
|
||||
"Der User <NAME_SENDER> hat den Umschlag <DOCUMENT_TITLE> gelöscht.",
|
||||
"",
|
||||
"Mit freundlichen Grüßen",
|
||||
"<NAME_PORTAL>"
|
||||
}
|
||||
|
||||
_DocumentCompletedBodyTemplate = New List(Of String) From {
|
||||
"Guten Tag, <NAME_RECEIVER>",
|
||||
"",
|
||||
"Das Dokument <DOCUMENT_TITLE> wurde von allen Beteiligten unterschrieben.",
|
||||
"",
|
||||
"Mit freundlichen Grüßen",
|
||||
"<NAME_PORTAL>"
|
||||
}
|
||||
End Sub
|
||||
|
||||
Private Sub InitDictionary(pEmailData As EmailData)
|
||||
_replaceDictionary = New Dictionary(Of String, String) From {
|
||||
{"<NAME_RECEIVER>", pEmailData.ReceiverName},
|
||||
{"<NAME_SENDER>", pEmailData.SenderName},
|
||||
{"<NAME_PORTAL>", DbConfig.ExternalProgramName},
|
||||
{"<SIGNATURE_TYPE>", "signieren"},
|
||||
{"<LINK_TO_DOCUMENT>", pEmailData.SignatureLink},
|
||||
{"<LINK_TO_DOCUMENT_TEXT>", $"{pEmailData.SignatureLink.Truncate(40)}.."},
|
||||
{"<DOCUMENT_TITLE>", pEmailData.EmailSubject},
|
||||
{"<MESSAGE>", pEmailData.Message}
|
||||
}
|
||||
End Sub
|
||||
|
||||
Public Sub FillDocumentReceivedEmailBody(pEmailData As EmailData)
|
||||
FillEmailBody(pEmailData, _DocumentReceivedBodyTemplate)
|
||||
End Sub
|
||||
|
||||
Public Sub FillEnvelopeDeletedEmailBody(pEmailData As EmailData)
|
||||
FillEmailBody(pEmailData, _DocumentDeletedBodyTemplate)
|
||||
End Sub
|
||||
|
||||
Public Sub FillDocumentSignedEmailBody(pEmailData As EmailData)
|
||||
FillEmailBody(pEmailData, _DocumentSignedBodyTemplate)
|
||||
End Sub
|
||||
|
||||
Public Sub FillDocumentCompletedEmailBody(pEmailData As EmailData)
|
||||
FillEmailBody(pEmailData, _DocumentCompletedBodyTemplate)
|
||||
End Sub
|
||||
|
||||
Public Sub FillEmailSubject(pEmailData As EmailData, pTemplate As String)
|
||||
InitDictionary(pEmailData)
|
||||
|
||||
Dim resultSubject As String = pTemplate
|
||||
|
||||
For Each dictItem As KeyValuePair(Of String, String) In _replaceDictionary
|
||||
If resultSubject.Contains(dictItem.Key) Then
|
||||
resultSubject = resultSubject.Replace(dictItem.Key, dictItem.Value)
|
||||
|
||||
End If
|
||||
Next
|
||||
|
||||
|
||||
End Sub
|
||||
|
||||
Public Sub FillEmailBody(pEmailData As EmailData, pTemplate As List(Of String))
|
||||
|
||||
InitDictionary(pEmailData)
|
||||
|
||||
Dim resultBody As String = ""
|
||||
|
||||
For Each lineItem As String In pTemplate
|
||||
Dim oLineValue As String = lineItem
|
||||
For Each dictItem As KeyValuePair(Of String, String) In _replaceDictionary
|
||||
If oLineValue.Contains(dictItem.Key) Then
|
||||
oLineValue = oLineValue.Replace(dictItem.Key, dictItem.Value)
|
||||
|
||||
End If
|
||||
Next
|
||||
resultBody += oLineValue + "<br/>"
|
||||
Next
|
||||
|
||||
pEmailData.EmailBody = resultBody
|
||||
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
@@ -2,11 +2,26 @@
|
||||
Public Property Id As Integer = 0
|
||||
Public Property UserId As Integer
|
||||
Public Property Title As String = ""
|
||||
Public Property ContractType As Constants.ContractType
|
||||
Public Property Status As Constants.EnvelopeStatus
|
||||
Public Property EnvelopeTypeId As Integer
|
||||
Public Property ContractType As Integer
|
||||
Public Property Status As Constants.EnvelopeStatus = Constants.EnvelopeStatus.EnvelopeCreated
|
||||
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.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
|
||||
|
||||
Public Property ExpiresWhen As Date
|
||||
Public Property ExpiresWarningWhen As Date
|
||||
Public Property ExpiresWhenDays As Integer
|
||||
Public Property ExpiresWarningWhenDays As Integer
|
||||
|
||||
Public Property FinalEmailToCreator As Constants.FinalEmailType
|
||||
Public Property FinalEmailToReceivers As Constants.FinalEmailType
|
||||
|
||||
Public Property Subject As String = My.Resources.Envelope.You_received_a_document_to_sign_
|
||||
Public Property Message As String = My.Resources.Envelope.Please_read_and_sign_this_document
|
||||
|
||||
Public Property AddedWhen As Date
|
||||
@@ -14,6 +29,20 @@
|
||||
|
||||
Public Property Documents As New List(Of EnvelopeDocument)
|
||||
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
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public ReadOnly Property IsAlreadySent As Boolean
|
||||
Get
|
||||
Return Status > Constants.EnvelopeStatus.EnvelopeSaved
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public ReadOnly Property StatusTranslated As String
|
||||
Get
|
||||
@@ -40,6 +69,10 @@
|
||||
oErrors.Add(My.Resources.Envelope.Missing_Receivers)
|
||||
End If
|
||||
|
||||
If Receivers.Any(Function(r) r.HasEmailAndName = False) Then
|
||||
oErrors.Add(My.Resources.Envelope.Incomplete_Receivers)
|
||||
End If
|
||||
|
||||
Return oErrors
|
||||
End Function
|
||||
|
||||
|
||||
@@ -17,4 +17,7 @@ Public Class EnvelopeDocument
|
||||
Public Property Filename As String
|
||||
|
||||
Public Property Filepath As String
|
||||
End Class
|
||||
|
||||
Public Property PageCount As Integer
|
||||
Public Property Byte_Data As Byte()
|
||||
End Class
|
||||
@@ -1,6 +1,12 @@
|
||||
Public Class EnvelopeHistoryEntry
|
||||
Public EnvelopeId As Integer
|
||||
Public UserReference As String
|
||||
Public Status As Constants.EnvelopeStatus
|
||||
Public ActionDate As Date = Now()
|
||||
Public Property EnvelopeId As Integer
|
||||
Public Property UserReference As String
|
||||
Public Property Status As Constants.EnvelopeStatus
|
||||
Public ReadOnly Property StatusTranslated As String
|
||||
Get
|
||||
Dim oStatus = Status.ToString()
|
||||
Return My.Resources.Model.ResourceManager.GetString(oStatus)
|
||||
End Get
|
||||
End Property
|
||||
Public Property ActionDate As Date = Now()
|
||||
End Class
|
||||
|
||||
@@ -48,15 +48,34 @@ Public Class EnvelopeReceiver
|
||||
|
||||
Public Property SignedDate As DateTime = DateTime.MinValue
|
||||
|
||||
Public ReadOnly Property SignedDateDisplayValue As String
|
||||
Get
|
||||
If SignedDate = DateTime.MinValue Then
|
||||
Return "-"
|
||||
Else
|
||||
Return SignedDate.ToString("G")
|
||||
End If
|
||||
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public ReadOnly Property HasId As Boolean
|
||||
Get
|
||||
Return Id > 0
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public ReadOnly Property HasEmailAndName As Boolean
|
||||
Get
|
||||
Return String.IsNullOrWhiteSpace(Email) = False And
|
||||
String.IsNullOrWhiteSpace(Name) = False
|
||||
End Get
|
||||
End Property
|
||||
|
||||
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)
|
||||
|
||||
27
EnvelopeGenerator.Common/Entities/EnvelopeType.vb
Normal file
27
EnvelopeGenerator.Common/Entities/EnvelopeType.vb
Normal file
@@ -0,0 +1,27 @@
|
||||
Public Class EnvelopeType
|
||||
|
||||
Public Property Id As Integer = 0
|
||||
Public Property Title As String
|
||||
Public Property UseAccessCode As Boolean
|
||||
Public Property ContractType As Integer ' Unbenutzt
|
||||
|
||||
Public Property Language As String
|
||||
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
|
||||
|
||||
Public Property ExpiresWhen As Date
|
||||
Public Property ExpiresWarningWhen As Date
|
||||
Public Property ExpiresWhenDays As Integer
|
||||
Public Property ExpiresWarningWhenDays As Integer
|
||||
|
||||
Public Property FinalEmailToCreator As Constants.FinalEmailType
|
||||
Public Property FinalEmailToReceivers As Constants.FinalEmailType
|
||||
|
||||
Public Overrides Function ToString() As String
|
||||
Return Title
|
||||
End Function
|
||||
|
||||
End Class
|
||||
@@ -3,6 +3,7 @@ Imports DigitalData.Modules.Logging
|
||||
|
||||
Public Class State
|
||||
Public Property UserId As Integer
|
||||
Public Property User As User
|
||||
Public Property Config As Config
|
||||
Public Property DbConfig As DbConfig
|
||||
Public Property LogConfig As LogConfig
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
Public Property Email As String
|
||||
Public Property Language As String
|
||||
|
||||
Public Property HasAccess As Boolean
|
||||
Public Property IsAdmin As Boolean
|
||||
|
||||
Public ReadOnly Property FullName() As String
|
||||
Get
|
||||
Return Prename + " " + Name
|
||||
|
||||
@@ -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>
|
||||
@@ -56,23 +58,27 @@
|
||||
<Reference Include="DevExpress.RichEdit.v21.2.Core, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||
<Reference Include="DevExpress.RichEdit.v21.2.Export, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||
<Reference Include="DevExpress.Sparkline.v21.2.Core, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||
<Reference Include="DevExpress.Utils.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
|
||||
<Reference Include="DevExpress.Xpo.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
|
||||
<Reference Include="DevExpress.XtraBars.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||
<Reference Include="DevExpress.XtraCharts.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||
<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, 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">
|
||||
@@ -124,27 +130,36 @@
|
||||
<Compile Include="Entities\ElementStatus.vb" />
|
||||
<Compile Include="Entities\EmailData.vb" />
|
||||
<Compile Include="Entities\EmailTemplate.vb" />
|
||||
<Compile Include="Services\TemplateService.vb" />
|
||||
<Compile Include="Entities\Envelope.vb" />
|
||||
<Compile Include="Entities\EnvelopeDocument.vb" />
|
||||
<Compile Include="Entities\EnvelopeDocumentElement.vb" />
|
||||
<Compile Include="Entities\EnvelopeHistoryEntry.vb" />
|
||||
<Compile Include="Entities\EnvelopeReceiver.vb" />
|
||||
<Compile Include="Entities\EnvelopeResponse.vb" />
|
||||
<Compile Include="Entities\EnvelopeType.vb" />
|
||||
<Compile Include="Entities\State.vb" />
|
||||
<Compile Include="Entities\User.vb" />
|
||||
<Compile Include="Helpers.vb" />
|
||||
<Compile Include="Jobs\CertificateDocumentJob.vb" />
|
||||
<Compile Include="Jobs\FinalizeDocument\FinalizeDocumentExceptions.vb" />
|
||||
<Compile Include="Jobs\FinalizeDocument\FinalizeDocumentJob.vb" />
|
||||
<Compile Include="Jobs\FinalizeDocument\PDFBurner.vb" />
|
||||
<Compile Include="Jobs\FinalizeDocument\PDFMerger.vb" />
|
||||
<Compile Include="Models\BaseModel.vb" />
|
||||
<Compile Include="Models\CertificateModel.vb" />
|
||||
<Compile Include="Models\ChartModel.vb" />
|
||||
<Compile Include="Models\ConfigModel.vb" />
|
||||
<Compile Include="Models\DocumentModel.vb" />
|
||||
<Compile Include="Models\ElementModel.vb" />
|
||||
<Compile Include="Models\DocumentStatusModel.vb" />
|
||||
<Compile Include="Models\ElementStatusModel.vb" />
|
||||
<Compile Include="Models\EmailModel.vb" />
|
||||
<Compile Include="Models\EmailTemplateModel.vb" />
|
||||
<Compile Include="Models\EnvelopeModel.vb" />
|
||||
<Compile Include="Models\HistoryModel.vb" />
|
||||
<Compile Include="Models\ReceiverModel.vb" />
|
||||
<Compile Include="Models\EnvelopeTypeModel.vb" />
|
||||
<Compile Include="Models\ReportModel.vb" />
|
||||
<Compile Include="Models\UserModel.vb" />
|
||||
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||
<Compile Include="My Project\Application.Designer.vb">
|
||||
@@ -162,9 +177,9 @@
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="Reports\ReportCreator.vb" />
|
||||
<Compile Include="Reports\ReportItem.vb" />
|
||||
<Compile Include="Reports\ReportSource.vb" />
|
||||
<Compile Include="Jobs\FinalizeDocument\ReportCreator.vb" />
|
||||
<Compile Include="Jobs\FinalizeDocument\ReportItem.vb" />
|
||||
<Compile Include="Jobs\FinalizeDocument\ReportSource.vb" />
|
||||
<Compile Include="Reports\rptEnvelopeHistory.Designer.vb">
|
||||
<DependentUpon>rptEnvelopeHistory.vb</DependentUpon>
|
||||
</Compile>
|
||||
@@ -172,6 +187,7 @@
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Services\ActionService.vb" />
|
||||
<Compile Include="Services\BaseService.vb" />
|
||||
<Compile Include="Services\EmailService.vb" />
|
||||
<Compile Include="Services\HistoryService.vb" />
|
||||
<Compile Include="Strings\Email.en.Designer.vb">
|
||||
@@ -204,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" />
|
||||
@@ -217,7 +235,7 @@
|
||||
<DependentUpon>rptEnvelopeHistory.vb</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Strings\Email.en.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Email.en.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
</EmbeddedResource>
|
||||
@@ -225,29 +243,34 @@
|
||||
<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>ResXFileCodeGenerator</Generator>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Email.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Strings\Model.en.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<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>ResXFileCodeGenerator</Generator>
|
||||
<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>
|
||||
@@ -263,6 +286,16 @@
|
||||
<Content Include="Images\circle.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<EmbeddedResource Include="Templates\document_access_code_de.html" />
|
||||
<EmbeddedResource Include="Templates\email_de.html" />
|
||||
</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,8 +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
|
||||
@@ -38,6 +58,11 @@ Public Class Helpers
|
||||
|
||||
End Function
|
||||
|
||||
Public Shared Function GetAccessCode() As String
|
||||
Return Guid.NewGuid().ToString("d").Substring(1, 6).ToUpper()
|
||||
End Function
|
||||
|
||||
|
||||
Public Shared Function ColorTypeToColor(pColorType As ColorType) As Color
|
||||
Select Case pColorType
|
||||
Case ColorType.ReceiverColor1
|
||||
@@ -94,4 +119,16 @@ Public Class Helpers
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Shared Async Function CopyFileAsync(sourceFile As String, destinationFile As String) As Task
|
||||
Dim fileOptions = IO.FileOptions.Asynchronous Or IO.FileOptions.SequentialScan
|
||||
Dim bufferSize = 4096
|
||||
|
||||
Using sourceStream = New FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, fileOptions)
|
||||
|
||||
Using destinationStream = New FileStream(destinationFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, bufferSize, fileOptions)
|
||||
Await sourceStream.CopyToAsync(destinationStream, bufferSize).ConfigureAwait(False)
|
||||
End Using
|
||||
End Using
|
||||
End Function
|
||||
End Class
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
Imports DigitalData.Modules.Database
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports Quartz
|
||||
|
||||
Public Class CertificateDocumentJob
|
||||
Implements IJob
|
||||
|
||||
Public Function Execute(pContext As IJobExecutionContext) As Task Implements IJob.Execute
|
||||
Dim oLogConfig As LogConfig = pContext.MergedJobDataMap.Item(Constants.LOGCONFIG)
|
||||
Dim oConnectionString As String = pContext.MergedJobDataMap.Item(Constants.DATABASE)
|
||||
Dim oLogger As Logger = oLogConfig.GetLogger()
|
||||
|
||||
Try
|
||||
Dim oDatabase As New MSSQLServer(oLogConfig, MSSQLServer.DecryptConnectionString(oConnectionString))
|
||||
Dim JobId = pContext.JobDetail.Key
|
||||
oLogger.Info("Starting job {0}", JobId)
|
||||
|
||||
Dim oCompleteStatus As Integer = Constants.EnvelopeStatus.EnvelopeCompletelySigned
|
||||
Dim oSql = $"SELECT * FROM TBSIG_ENVELOPE WHERE STATUS = {oCompleteStatus}"
|
||||
Dim oTable = oDatabase.GetDatatable(oSql)
|
||||
|
||||
oLogger.Info("Found [{0}] completed envelopes.", oTable.Rows.Count)
|
||||
|
||||
' Do important work...
|
||||
|
||||
oLogger.Info("Completed job {0}", JobId)
|
||||
Return Task.FromResult(True)
|
||||
|
||||
Catch ex As Exception
|
||||
oLogger.Warn("Certificate Document job failed!")
|
||||
oLogger.Error(ex)
|
||||
|
||||
Return Task.FromException(ex)
|
||||
End Try
|
||||
End Function
|
||||
End Class
|
||||
@@ -0,0 +1,52 @@
|
||||
Namespace Jobs.FinalizeDocument
|
||||
Public Class FinalizeDocumentExceptions
|
||||
|
||||
Public Class MergeDocumentException
|
||||
Inherits ApplicationException
|
||||
|
||||
Public Sub New(message As String)
|
||||
MyBase.New(message)
|
||||
End Sub
|
||||
|
||||
Public Sub New(message As String, innerException As Exception)
|
||||
MyBase.New(message, innerException)
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
Public Class BurnAnnotationException
|
||||
Inherits ApplicationException
|
||||
|
||||
Public Sub New(message As String)
|
||||
MyBase.New(message)
|
||||
End Sub
|
||||
|
||||
Public Sub New(message As String, innerException As Exception)
|
||||
MyBase.New(message, innerException)
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
Public Class CreateReportException
|
||||
Inherits ApplicationException
|
||||
|
||||
Public Sub New(message As String)
|
||||
MyBase.New(message)
|
||||
End Sub
|
||||
|
||||
Public Sub New(message As String, innerException As Exception)
|
||||
MyBase.New(message, innerException)
|
||||
End Sub
|
||||
End Class
|
||||
Public Class ExportDocumentException
|
||||
Inherits ApplicationException
|
||||
|
||||
Public Sub New(message As String)
|
||||
MyBase.New(message)
|
||||
End Sub
|
||||
|
||||
Public Sub New(message As String, innerException As Exception)
|
||||
MyBase.New(message, innerException)
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
End Class
|
||||
End Namespace
|
||||
@@ -0,0 +1,452 @@
|
||||
Imports DigitalData.Modules.Database
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports GdPicture14
|
||||
Imports Quartz
|
||||
Imports System.Security.Cryptography
|
||||
Imports System.IO
|
||||
Imports EnvelopeGenerator.Common.Jobs.FinalizeDocument.FinalizeDocumentExceptions
|
||||
Imports EnvelopeGenerator.Common.Jobs.FinalizeDocument
|
||||
Imports EnvelopeGenerator.Common.Constants
|
||||
Imports DevExpress.DataProcessing
|
||||
Imports System.Data.SqlClient
|
||||
|
||||
Namespace Jobs
|
||||
Public Class FinalizeDocumentJob
|
||||
Implements IJob
|
||||
|
||||
Private ReadOnly LicenseManager As New LicenseManager()
|
||||
Private GdViewer As GdViewer
|
||||
|
||||
Private LogConfig As LogConfig
|
||||
Private Logger As Logger
|
||||
Private Database As MSSQLServer
|
||||
Private Config As DbConfig
|
||||
|
||||
Private ConfigModel As ConfigModel
|
||||
Private EnvelopeModel As EnvelopeModel
|
||||
Private ReportModel As ReportModel
|
||||
|
||||
Private ActionService As ActionService
|
||||
|
||||
Private PDFBurner As PDFBurner
|
||||
Private PDFMerger As PDFMerger
|
||||
Private ReportCreator As ReportCreator
|
||||
|
||||
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
|
||||
|
||||
Public Function Execute(pContext As IJobExecutionContext) As Task Implements IJob.Execute
|
||||
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)
|
||||
|
||||
Try
|
||||
Logger.Debug("Loading GdViewer..")
|
||||
GdViewer = New GdViewer()
|
||||
LicenseManager.RegisterKEY(oGdPictureKey)
|
||||
|
||||
Logger.Debug("Loading Database..")
|
||||
Database = GetDatabase(pContext, LogConfig)
|
||||
|
||||
Logger.Debug("Loading Models & Services")
|
||||
Dim oState = GetState()
|
||||
InitializeModels(oState)
|
||||
|
||||
Logger.Debug("Loading Configuration..")
|
||||
Config = ConfigModel.LoadConfiguration()
|
||||
oState.DbConfig = Config
|
||||
|
||||
InitializeServices(oState)
|
||||
|
||||
Logger.Debug("Loading PDFBurner..")
|
||||
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)
|
||||
|
||||
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()) >= {CompleteWaitTime} ORDER BY GUID"
|
||||
Dim oTable = Database.GetDatatable(oSql)
|
||||
|
||||
Dim oEnvelopeIds As List(Of Integer) = oTable.Rows.Cast(Of DataRow).
|
||||
Select(Function(r) r.Item("GUID")).
|
||||
Cast(Of Integer).
|
||||
ToList()
|
||||
|
||||
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..")
|
||||
Try
|
||||
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($"Unhandled exception while working envelope [{oId}] - [{ex.Message}]")
|
||||
End Try
|
||||
|
||||
|
||||
oCurrent += 1
|
||||
Logger.Info("Envelope finalized!")
|
||||
|
||||
Next
|
||||
|
||||
Logger.Debug("Completed job {0} successfully!", JobId)
|
||||
Catch ex As MergeDocumentException
|
||||
Logger.Warn("Certificate Document job failed at step: Merging documents!")
|
||||
Logger.Error(ex)
|
||||
|
||||
Catch ex As ExportDocumentException
|
||||
Logger.Warn("Certificate Document job failed at step: Exporting document!")
|
||||
Logger.Error(ex)
|
||||
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Certificate Document job failed!")
|
||||
Logger.Error(ex)
|
||||
Finally
|
||||
Logger.Info("Job execution for [{0}] ended", JobId)
|
||||
End Try
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
End If
|
||||
|
||||
If oMailToReceivers <> FinalEmailType.No Then
|
||||
Logger.Debug("Sending emails to receivers..")
|
||||
SendFinalEmailToReceivers(pEnvelope) ', pAttachment
|
||||
End If
|
||||
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Private Function SendFinalEmailToCreator(pEnvelope As Envelope) As Boolean ', pAttachment As String
|
||||
Dim oIncludeAttachment = SendFinalEmailWithAttachment(pEnvelope.FinalEmailToCreator)
|
||||
' Dim oAttachment = String.Empty
|
||||
|
||||
Logger.Debug("Attachment included: [{0}]", oIncludeAttachment)
|
||||
If oIncludeAttachment Then
|
||||
'oAttachment = pAttachment
|
||||
End If
|
||||
|
||||
If ActionService.CompleteEnvelope(pEnvelope) = False Then ', oAttachment
|
||||
Logger.Error("Envelope could not be completed for receiver [{0}]", pEnvelope.User.Email)
|
||||
Return False
|
||||
End If
|
||||
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Private Function SendFinalEmailToReceivers(pEnvelope As Envelope) As Boolean ', pAttachment As String
|
||||
Dim oIncludeAttachment = SendFinalEmailWithAttachment(pEnvelope.FinalEmailToReceivers)
|
||||
'Dim oAttachment = String.Empty
|
||||
|
||||
Logger.Debug("Attachment included: [{0}]", oIncludeAttachment)
|
||||
If oIncludeAttachment Then
|
||||
|
||||
' oAttachment = pAttachment
|
||||
End If
|
||||
|
||||
For Each oReceiver In pEnvelope.Receivers
|
||||
If ActionService.CompleteEnvelope(pEnvelope, oReceiver) = False Then ', oAttachment
|
||||
Logger.Error("Envelope could not be completed for receiver [{0}]", oReceiver.Email)
|
||||
Return False
|
||||
End If
|
||||
Next
|
||||
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Private Function SendFinalEmailWithAttachment(pType As FinalEmailType)
|
||||
If pType = FinalEmailType.YesWithAttachment Then
|
||||
Return True
|
||||
Else
|
||||
Return False
|
||||
End If
|
||||
End Function
|
||||
|
||||
Private Function BurnAnnotationsToPdf(pEnvelopeData As EnvelopeData) As Byte()
|
||||
Dim pEnvelopeId = pEnvelopeData.EnvelopeId
|
||||
|
||||
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
|
||||
|
||||
|
||||
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()
|
||||
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, 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)
|
||||
Dim oRow As DataRow = oTable.Rows.Cast(Of DataRow).SingleOrDefault()
|
||||
If oRow Is Nothing Then
|
||||
Return Nothing
|
||||
End If
|
||||
|
||||
Dim oAnnotationData = GetAnnotationData(pEnvelopeId)
|
||||
Dim oData As New EnvelopeData With {
|
||||
.EnvelopeId = pEnvelopeId,
|
||||
.DocumentPath = oRow.ItemEx("FILEPATH", ""),
|
||||
.AnnotationData = oAnnotationData,
|
||||
.DocAsByte = DirectCast(oRow.Item("BYTE_DATA"), Byte()),
|
||||
.EnvelopeUUID = oRow.ItemEx("ENVELOPE_UUID", "")
|
||||
}
|
||||
|
||||
Logger.Debug("Document path: [{0}]", oData.DocumentPath)
|
||||
|
||||
Return oData
|
||||
End Function
|
||||
|
||||
Private Function GetAnnotationData(pEnvelopeId As Integer) As List(Of String)
|
||||
Dim oSql = $"SELECT VALUE FROM TBSIG_DOCUMENT_STATUS WHERE ENVELOPE_ID = {pEnvelopeId}"
|
||||
Dim oTable As DataTable = Database.GetDatatable(oSql)
|
||||
|
||||
Return oTable.Rows.Cast(Of DataRow).
|
||||
Select(Function(r) r.ItemEx("VALUE", String.Empty)).
|
||||
Cast(Of String).
|
||||
ToList()
|
||||
|
||||
End Function
|
||||
|
||||
Private Sub InitializeServices(pState As State)
|
||||
ActionService = New ActionService(pState)
|
||||
End Sub
|
||||
|
||||
Private Sub InitializeModels(pState As State)
|
||||
ConfigModel = New ConfigModel(pState)
|
||||
EnvelopeModel = New EnvelopeModel(pState)
|
||||
ReportModel = New ReportModel(pState)
|
||||
End Sub
|
||||
|
||||
Private Function GetDatabase(pContext As IJobExecutionContext, pLogConfig As LogConfig) As MSSQLServer
|
||||
Dim oConnectionString As String = pContext.MergedJobDataMap.Item(Constants.DATABASE)
|
||||
Dim Database = New MSSQLServer(pLogConfig, MSSQLServer.DecryptConnectionString(oConnectionString))
|
||||
|
||||
Return Database
|
||||
End Function
|
||||
|
||||
Private Function GetState() As State
|
||||
Return New State With {
|
||||
.LogConfig = LogConfig,
|
||||
.Database = Database,
|
||||
.UserId = 0,
|
||||
.Config = Nothing,
|
||||
.DbConfig = Nothing
|
||||
}
|
||||
End Function
|
||||
End Class
|
||||
End Namespace
|
||||
222
EnvelopeGenerator.Common/Jobs/FinalizeDocument/PDFBurner.vb
Normal file
222
EnvelopeGenerator.Common/Jobs/FinalizeDocument/PDFBurner.vb
Normal file
@@ -0,0 +1,222 @@
|
||||
Imports System.Drawing
|
||||
Imports System.IO
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports GdPicture14
|
||||
Imports Newtonsoft.Json
|
||||
Imports EnvelopeGenerator.Common.Jobs.FinalizeDocument.FinalizeDocumentExceptions
|
||||
|
||||
Namespace Jobs.FinalizeDocument
|
||||
Public Class PDFBurner
|
||||
Inherits BaseClass
|
||||
|
||||
Private ReadOnly Manager As AnnotationManager
|
||||
Private ReadOnly LicenseManager As LicenseManager
|
||||
|
||||
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, 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()
|
||||
Dim oResult As GdPictureStatus
|
||||
|
||||
Try
|
||||
Using oSourceStream As New MemoryStream(pSourceBuffer)
|
||||
oResult = Manager.InitFromStream(oSourceStream)
|
||||
If oResult <> GdPictureStatus.OK Then
|
||||
Throw New BurnAnnotationException($"Could not open document for burning: [{oResult}]")
|
||||
End If
|
||||
|
||||
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}]")
|
||||
End If
|
||||
|
||||
Using oNewStream As New MemoryStream()
|
||||
oResult = Manager.SaveDocumentToPDF(oNewStream)
|
||||
If oResult <> GdPictureStatus.OK Then
|
||||
Throw New BurnAnnotationException($"Could not save document to stream: [{oResult}]")
|
||||
End If
|
||||
|
||||
Manager.Close()
|
||||
|
||||
Return oNewStream.ToArray()
|
||||
End Using
|
||||
End Using
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
|
||||
Return Nothing
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private Function AddInstantJSONAnnotationToPDF(pInstantJSON As String) As Boolean
|
||||
Try
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Could not create annotation from InstantJSON")
|
||||
Logger.Error(ex)
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private Function AddImageAnnotation(pAnnotation As Annotation, pAttachments As Dictionary(Of String, Attachment)) As Boolean
|
||||
Try
|
||||
Dim oAttachment = pAttachments.Where(Function(a) a.Key = pAnnotation.imageAttachmentId).
|
||||
SingleOrDefault()
|
||||
|
||||
' 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)
|
||||
Manager.AddEmbeddedImageAnnotFromBase64(oAttachment.Value.binary, oX, oY, oWidth, oHeight)
|
||||
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Could not add image annotation!")
|
||||
Logger.Error(ex)
|
||||
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private Function AddInkAnnotation(pAnnotation As Annotation) As Boolean
|
||||
Try
|
||||
Dim oSegments = pAnnotation.lines.points
|
||||
Dim oColor = ColorTranslator.FromHtml(pAnnotation.strokeColor)
|
||||
Manager.SelectPage(pAnnotation.pageIndex + 1)
|
||||
|
||||
For Each oSegment As List(Of List(Of Single)) In oSegments
|
||||
Dim oPoints = oSegment.
|
||||
Select(AddressOf ToPointF).
|
||||
ToArray()
|
||||
|
||||
Manager.AddFreeHandAnnot(oColor, oPoints)
|
||||
Next
|
||||
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Could not add image annotation!")
|
||||
Logger.Error(ex)
|
||||
|
||||
Return False
|
||||
End Try
|
||||
|
||||
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))
|
||||
End Function
|
||||
|
||||
Private Function ToInches(pValue As Double) As Double
|
||||
Return pValue / 72
|
||||
End Function
|
||||
|
||||
Private Function ToInches(pValue As Single) As Single
|
||||
Return pValue / 72
|
||||
End Function
|
||||
|
||||
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
|
||||
Public Property id As String
|
||||
Public Property bbox As List(Of Double)
|
||||
Public Property type As String
|
||||
Public Property isSignature As Boolean
|
||||
Public Property imageAttachmentId As String
|
||||
Public Property lines As Lines
|
||||
Public Property pageIndex As Integer
|
||||
Public Property strokeColor As String
|
||||
End Class
|
||||
|
||||
Friend Class Lines
|
||||
Public Property points As List(Of List(Of List(Of Single)))
|
||||
End Class
|
||||
|
||||
Friend Class Attachment
|
||||
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
|
||||
71
EnvelopeGenerator.Common/Jobs/FinalizeDocument/PDFMerger.vb
Normal file
71
EnvelopeGenerator.Common/Jobs/FinalizeDocument/PDFMerger.vb
Normal file
@@ -0,0 +1,71 @@
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports EnvelopeGenerator.Common.Jobs.FinalizeDocument.FinalizeDocumentExceptions
|
||||
Imports GdPicture14
|
||||
Imports System.IO
|
||||
|
||||
Public Class PDFMerger
|
||||
Inherits BaseClass
|
||||
|
||||
Private ReadOnly Manager As AnnotationManager
|
||||
Private ReadOnly LicenseManager As LicenseManager
|
||||
|
||||
Private Const ALLOW_RASTERIZATION = True
|
||||
Private Const ALLOW_VECTORIZATION = True
|
||||
|
||||
Private ReadOnly PDFAConformanceLevel As PdfConversionConformance = PdfConversionConformance.PDF_A_1b
|
||||
|
||||
Public Sub New(pLogConfig As LogConfig, pGDPictureLicenseKey As String)
|
||||
MyBase.New(pLogConfig)
|
||||
|
||||
LicenseManager = New LicenseManager()
|
||||
LicenseManager.RegisterKEY(pGDPictureLicenseKey)
|
||||
|
||||
Manager = New AnnotationManager()
|
||||
End Sub
|
||||
|
||||
Public Function MergeDocuments(pDocument As Byte(), pReport As Byte()) As Byte()
|
||||
Using oDocumentStream As New MemoryStream(pDocument)
|
||||
Using oReportStream As New MemoryStream(pReport)
|
||||
Using oFinalStream As New MemoryStream()
|
||||
Using oDocumentPDF As New GdPicturePDF()
|
||||
Using oReportPDF As New GdPicturePDF()
|
||||
Dim oStatus As GdPictureStatus = GdPictureStatus.OK
|
||||
|
||||
' Load the source file into memory
|
||||
oDocumentPDF.LoadFromStream(oDocumentStream, True)
|
||||
|
||||
oStatus = oDocumentPDF.GetStat()
|
||||
If oStatus <> GdPictureStatus.OK Then
|
||||
Throw New MergeDocumentException($"Document could not be loaded: {oStatus}")
|
||||
End If
|
||||
|
||||
' Load the report file into memory
|
||||
oReportPDF.LoadFromStream(oReportStream, True)
|
||||
oStatus = oReportPDF.GetStat()
|
||||
If oStatus <> GdPictureStatus.OK Then
|
||||
Throw New MergeDocumentException($"Report could not be loaded: {oStatus}")
|
||||
End If
|
||||
|
||||
' Merge the documents
|
||||
Dim oMergedPDF = oDocumentPDF.Merge2Documents(oDocumentPDF, oReportPDF)
|
||||
oStatus = oMergedPDF.GetStat()
|
||||
If oStatus <> GdPictureStatus.OK Then
|
||||
Throw New MergeDocumentException($"Documents could not be merged: {oStatus}")
|
||||
End If
|
||||
|
||||
' Convert to PDF/A
|
||||
oMergedPDF.ConvertToPDFA(oFinalStream, PDFAConformanceLevel, ALLOW_VECTORIZATION, ALLOW_RASTERIZATION)
|
||||
oStatus = oDocumentPDF.GetStat()
|
||||
If oStatus <> GdPictureStatus.OK Then
|
||||
Throw New MergeDocumentException($"Document could not be converted to PDF/A: {oStatus}")
|
||||
End If
|
||||
|
||||
Return oFinalStream.ToArray()
|
||||
End Using
|
||||
End Using
|
||||
End Using
|
||||
End Using
|
||||
End Using
|
||||
End Function
|
||||
End Class
|
||||
@@ -0,0 +1,91 @@
|
||||
Imports System.IO
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports EnvelopeGenerator.Common.Jobs.FinalizeDocument.FinalizeDocumentExceptions
|
||||
|
||||
Public Class ReportCreator
|
||||
Inherits BaseClass
|
||||
|
||||
Private Envelope As Envelope
|
||||
Private ReadOnly ReportModel As ReportModel
|
||||
Private ReadOnly EnvelopeModel As EnvelopeModel
|
||||
|
||||
Public Sub New(pLogConfig As LogConfig, pState As State)
|
||||
MyBase.New(pLogConfig)
|
||||
|
||||
ReportModel = New ReportModel(pState)
|
||||
EnvelopeModel = New EnvelopeModel(pState)
|
||||
End Sub
|
||||
|
||||
Public Function CreateReport(pEnvelope As Envelope) As Byte()
|
||||
Try
|
||||
Logger.Debug("Loading report data..")
|
||||
Dim oTable = ReportModel.List(pEnvelope.Id)
|
||||
Dim oItems = GetReportSource(oTable)
|
||||
|
||||
Envelope = pEnvelope
|
||||
|
||||
If oItems.Count = 0 Then
|
||||
Throw New CreateReportException("No report data found!")
|
||||
End If
|
||||
|
||||
Logger.Debug("Creating report with [{0}] items..", oItems.Count)
|
||||
Dim oBuffer = DoCreateReport(oItems)
|
||||
Logger.Debug("Report created!")
|
||||
|
||||
Return oBuffer
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw New CreateReportException("Could not prepare report data!", ex)
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private Function GetReportSource(pDataTable As DataTable) As List(Of ReportItem)
|
||||
Logger.Debug("Preparing report data")
|
||||
Return pDataTable.Rows.
|
||||
Cast(Of DataRow).
|
||||
Select(AddressOf ToReportItem).
|
||||
OrderByDescending(Function(r) r.ItemDate).
|
||||
ToList()
|
||||
End Function
|
||||
|
||||
Private Function DoCreateReport(pReportItems As List(Of ReportItem)) As Byte()
|
||||
Dim oItems = pReportItems.Select(AddressOf MergeEnvelope).ToList()
|
||||
Dim oSource As New ReportSource With {.Items = oItems}
|
||||
Dim oReport As New rptEnvelopeHistory() With {.DataSource = oSource, .DataMember = "Items"}
|
||||
|
||||
Logger.Debug("Creating report in memory..")
|
||||
oReport.CreateDocument()
|
||||
|
||||
Logger.Debug("Exporting report to stream..")
|
||||
Using oStream As New MemoryStream()
|
||||
oReport.ExportToPdf(oStream)
|
||||
|
||||
Logger.Debug("Writing report to buffer..")
|
||||
Return oStream.ToArray()
|
||||
End Using
|
||||
End Function
|
||||
|
||||
Private Function MergeEnvelope(pItem As ReportItem) As ReportItem
|
||||
If pItem.Envelope Is Nothing Then
|
||||
pItem.Envelope = Envelope
|
||||
End If
|
||||
Return pItem
|
||||
End Function
|
||||
|
||||
Private Function ToReportItem(pRow As DataRow) As ReportItem
|
||||
Try
|
||||
Return New ReportItem() With {
|
||||
.EnvelopeId = pRow.Item("ENVELOPE_ID"),
|
||||
.EnvelopeTitle = pRow.ItemEx("HEAD_TITLE", String.Empty),
|
||||
.EnvelopeSubject = pRow.ItemEx("HEAD_SUBJECT", String.Empty),
|
||||
.ItemDate = pRow.ItemEx(Of Date)("POS_WHEN", Nothing),
|
||||
.ItemStatus = pRow.ItemEx("POS_STATUS", 0),
|
||||
.ItemUserReference = pRow.ItemEx("POS_WHO", "")
|
||||
}
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw New CreateReportException("Could not read data from database!", ex)
|
||||
End Try
|
||||
End Function
|
||||
End Class
|
||||
@@ -1,4 +1,6 @@
|
||||
Public Class ReportItem
|
||||
Imports System.Windows.Forms.VisualStyles.VisualStyleElement
|
||||
|
||||
Public Class ReportItem
|
||||
|
||||
Public Property Envelope As Envelope
|
||||
Public Property EnvelopeId As Integer
|
||||
@@ -6,6 +8,13 @@
|
||||
Public Property EnvelopeSubject As String
|
||||
|
||||
Public Property ItemStatus As Constants.EnvelopeStatus
|
||||
Public ReadOnly Property ItemStatusTranslated As String
|
||||
Get
|
||||
Dim oStatus = ItemStatus.ToString()
|
||||
Return My.Resources.Model.ResourceManager.GetString(oStatus)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public Property ItemUserReference As String
|
||||
Public Property ItemDate As Date
|
||||
|
||||
@@ -31,7 +31,7 @@ Public Class CertificateModel
|
||||
Dim oCommand As New SqlCommand(oSql)
|
||||
oCommand.Parameters.Add("ENVELOPE_ID", SqlDbType.Int).Value = pEnvelope.Id
|
||||
oCommand.Parameters.Add("ENVELOPE_UUID", SqlDbType.NVarChar).Value = pEnvelope.Uuid
|
||||
oCommand.Parameters.Add("ENVELOPE_SUBJECT", SqlDbType.NVarChar).Value = pEnvelope.Subject
|
||||
oCommand.Parameters.Add("ENVELOPE_SUBJECT", SqlDbType.NVarChar).Value = String.Empty
|
||||
oCommand.Parameters.Add("CREATOR_ID", SqlDbType.Int).Value = pEnvelope.UserId
|
||||
oCommand.Parameters.Add("CREATOR_NAME", SqlDbType.NVarChar).Value = pEnvelope.User.FullName
|
||||
oCommand.Parameters.Add("CREATOR_EMAIL", SqlDbType.NVarChar).Value = pEnvelope.User.Email
|
||||
|
||||
28
EnvelopeGenerator.Common/Models/ChartModel.vb
Normal file
28
EnvelopeGenerator.Common/Models/ChartModel.vb
Normal file
@@ -0,0 +1,28 @@
|
||||
Imports System.Data.SqlClient
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports DigitalData.Modules.Logging
|
||||
|
||||
Public Class ChartModel
|
||||
Inherits BaseModel
|
||||
|
||||
Public Sub New(pState As State)
|
||||
MyBase.New(pState)
|
||||
|
||||
End Sub
|
||||
|
||||
Public Function LoadPIEExample() As DataTable
|
||||
Try
|
||||
Dim oSQL As String
|
||||
oSQL = " SELECT 'ALLE' as Argument, 100 as Value"
|
||||
oSQL += " UNION "
|
||||
oSQL += " SELECT 'Komplett', 33 "
|
||||
|
||||
Dim oTable As DataTable = Database.GetDatatable(oSQL)
|
||||
|
||||
Return oTable
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Return Nothing
|
||||
End Try
|
||||
End Function
|
||||
End Class
|
||||
@@ -13,29 +13,24 @@ Public Class ConfigModel
|
||||
Try
|
||||
Dim oSql As String = "SELECT TOP 1 * FROM TBSIG_CONFIG"
|
||||
Dim oTable As DataTable = Database.GetDatatable(oSql)
|
||||
Dim oRow = oTable.Rows.Item(0)
|
||||
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)
|
||||
Return New DbConfig()
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Function GetUserId() As Integer
|
||||
Try
|
||||
Dim oUserId As Integer = Database.GetScalarValue($"SELECT GUID FROM TBDD_USER WHERE USERNAME = '{Environment.UserName}'")
|
||||
Return oUserId
|
||||
|
||||
Catch ex As Exception
|
||||
Return 0
|
||||
End Try
|
||||
End Function
|
||||
|
||||
|
||||
End Class
|
||||
|
||||
@@ -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, WF_ID) "
|
||||
oSql += " VALUES (@EMAIL_ADRESS, @EMAIL_SUBJ, @EMAIL_BODY, @ADDED_WHO, @SENDING_PROFILE, @REFERENCE_ID, @REFERENCE_STRING, @REMINDER_TYPE_ID, @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,7 +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("WF_ID", SqlDbType.Int).Value = 202377 ' Wegen DB-Trigger MUSS dieser Wert gesetzt werden
|
||||
'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
|
||||
|
||||
31
EnvelopeGenerator.Common/Models/EmailTemplateModel.vb
Normal file
31
EnvelopeGenerator.Common/Models/EmailTemplateModel.vb
Normal file
@@ -0,0 +1,31 @@
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports EnvelopeGenerator.Common.Constants
|
||||
|
||||
Public Class EmailTemplateModel
|
||||
Inherits BaseModel
|
||||
|
||||
Public Sub New(pState As State)
|
||||
MyBase.New(pState)
|
||||
End Sub
|
||||
|
||||
Private Function ToEmailTemplate(pRow As DataRow) As EmailTemplate
|
||||
Return New EmailTemplate() With {
|
||||
.Id = pRow.ItemEx("GUID", 0),
|
||||
.Name = pRow.ItemEx("NAME", ""),
|
||||
.Body = pRow.ItemEx("BODY", ""),
|
||||
.Subject = pRow.ItemEx("SUBJECT", "")
|
||||
}
|
||||
End Function
|
||||
|
||||
Public Function GetById(pEmailTemplateName As EmailTemplateType) As EmailTemplate
|
||||
Dim oSql As String = $"SELECT * FROM TBSIG_EMAIL_TEMPLATE WHERE NAME = '{pEmailTemplateName}'"
|
||||
Dim oTable As DataTable = Database.GetDatatable(oSql)
|
||||
|
||||
If oTable.Rows.Count = 0 Then
|
||||
Return Nothing
|
||||
End If
|
||||
|
||||
Dim oRow = oTable.Rows.Item(0)
|
||||
Return ToEmailTemplate(oRow)
|
||||
End Function
|
||||
End Class
|
||||
@@ -2,13 +2,16 @@
|
||||
Imports System.Web.UI.WebControls
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports EnvelopeGenerator.Common.Constants
|
||||
|
||||
Public Class EnvelopeModel
|
||||
Inherits BaseModel
|
||||
|
||||
Private ReadOnly UserModel As UserModel
|
||||
Private ReadOnly ReceiverModel As ReceiverModel
|
||||
Private ReadOnly HistoryModel As HistoryModel
|
||||
Private ReadOnly DocumentModel As DocumentModel
|
||||
Private ReadOnly EnvelopeTypeModel As EnvelopeTypeModel
|
||||
|
||||
Public Sub New(pState As State)
|
||||
MyBase.New(pState)
|
||||
@@ -16,25 +19,50 @@ Public Class EnvelopeModel
|
||||
UserModel = New UserModel(pState)
|
||||
ReceiverModel = New ReceiverModel(pState)
|
||||
DocumentModel = New DocumentModel(pState)
|
||||
HistoryModel = New HistoryModel(pState)
|
||||
EnvelopeTypeModel = New EnvelopeTypeModel(pState)
|
||||
End Sub
|
||||
|
||||
Private Function ToEnvelope(pRow As DataRow) As Envelope
|
||||
Dim oEnvelope = New Envelope() With {
|
||||
.Id = pRow.ItemEx("GUID", 0),
|
||||
.Title = pRow.ItemEx("TITLE", ""),
|
||||
.ContractType = ObjectEx.ToEnum(Of Constants.ContractType)(pRow.ItemEx("CONTRACT_TYPE", Constants.ContractType.Contract.ToString())),
|
||||
.EnvelopeTypeId = pRow.ItemEx("ENVELOPE_TYPE", 0),
|
||||
.ContractType = pRow.ItemEx("CONTRACT_TYPE", 0),
|
||||
.Uuid = pRow.ItemEx("ENVELOPE_UUID", ""),
|
||||
.Subject = pRow.ItemEx("SUBJECT", ""),
|
||||
.Message = pRow.ItemEx("MESSAGE", ""),
|
||||
.UserId = pRow.ItemEx("USER_ID", 0),
|
||||
.Language = pRow.ItemEx("LANGUAGE", "de-DE"),
|
||||
.Status = ObjectEx.ToEnum(Of Constants.EnvelopeStatus)(pRow.ItemEx("STATUS", Constants.EnvelopeStatus.EnvelopeCreated.ToString())),
|
||||
.AddedWhen = pRow.Item("ADDED_WHEN"),
|
||||
.User = New User()
|
||||
.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),
|
||||
.ExpiresWhenDays = pRow.ItemEx("EXPIRES_WHEN_DAYS", 0),
|
||||
.ExpiresWarningWhenDays = pRow.ItemEx("EXPIRES_WARNING_WHEN_DAYS", 0),
|
||||
.SendReminderEmails = pRow.ItemEx("SEND_REMINDER_EMAILS", False),
|
||||
.FirstReminderDays = pRow.ItemEx("FIRST_REMINDER_DAYS", 0),
|
||||
.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())),
|
||||
.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)
|
||||
oEnvelope.History = HistoryModel.List(oEnvelope.Id)
|
||||
oEnvelope.EnvelopeType = EnvelopeTypeModel.GetById(oEnvelope.EnvelopeTypeId)
|
||||
|
||||
Return oEnvelope
|
||||
End Function
|
||||
@@ -57,9 +85,9 @@ Public Class EnvelopeModel
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Function GetById(pEnvelopeId As String) As Envelope
|
||||
Public Function GetById(pEnvelopeId As Integer) As Envelope
|
||||
Try
|
||||
Dim oSql = $"SELECT * FROM [dbo].[TBSIG_ENVELOPE] WHERE GUID = '{pEnvelopeId}'"
|
||||
Dim oSql = $"SELECT * FROM [dbo].[TBSIG_ENVELOPE] WHERE GUID = {pEnvelopeId}"
|
||||
Dim oTable = Database.GetDatatable(oSql)
|
||||
|
||||
Return ToEnvelope(oTable)
|
||||
@@ -71,7 +99,7 @@ Public Class EnvelopeModel
|
||||
|
||||
Public Function List() As IEnumerable(Of Envelope)
|
||||
Try
|
||||
Dim oSql = $"EXEC PRSIG_GET_ENVELOPES_FOR_USER {State.UserId}"
|
||||
Dim oSql = $"EXEC [dbo].[PRSIG_GET_ENVELOPES_FOR_USER] {State.UserId}"
|
||||
Dim oTable = Database.GetDatatable(oSql)
|
||||
|
||||
Return oTable?.Rows.Cast(Of DataRow).
|
||||
@@ -85,7 +113,7 @@ Public Class EnvelopeModel
|
||||
|
||||
Public Function ListCompleted() As IEnumerable(Of Envelope)
|
||||
Try
|
||||
Dim oSql = $"SELECT * FROM [dbo].[TBSIG_ENVELOPE] WHERE USER_ID = {State.UserId} AND STATUS = 4"
|
||||
Dim oSql = $"EXEC [dbo].[PRSIG_GET_CLOSED_ENVELOPES_FOR_USER] {State.UserId}"
|
||||
Dim oTable = Database.GetDatatable(oSql)
|
||||
|
||||
Return oTable?.Rows.Cast(Of DataRow).
|
||||
@@ -116,20 +144,21 @@ Public Class EnvelopeModel
|
||||
|
||||
Public Function Insert(pEnvelope As Envelope) As Boolean
|
||||
Try
|
||||
Dim oSql = "INSERT INTO [dbo].[TBSIG_ENVELOPE] (SUBJECT, MESSAGE, ENVELOPE_UUID, STATUS, USER_ID, TITLE, CONTRACT_TYPE) "
|
||||
oSql += " VALUES (@SUBJECT, @MESSAGE, @UUID, @STATUS, @USER_ID, @TITLE, @CONTRACT_TYPE)"
|
||||
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("SUBJECT", SqlDbType.NVarChar).Value = String.Empty
|
||||
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("TITLE", SqlDbType.NVarChar).Value = pEnvelope.Title
|
||||
oCommand.Parameters.Add("CONTRACT_TYPE", SqlDbType.Int).Value = pEnvelope.ContractType
|
||||
'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)
|
||||
SetEnvelopeDate(pEnvelope) 'TODO JJ fragen
|
||||
SetEnvelopeDate(pEnvelope)
|
||||
Return True
|
||||
Else
|
||||
Return False
|
||||
@@ -144,23 +173,48 @@ Public Class EnvelopeModel
|
||||
Public Function Update(pEnvelope As Envelope, pTransaction As SqlTransaction) As Boolean
|
||||
Try
|
||||
Dim oSql = "UPDATE [dbo].[TBSIG_ENVELOPE] SET "
|
||||
oSql += " [SUBJECT] = @SUBJECT, "
|
||||
oSql += " [MESSAGE] = @MESSAGE, "
|
||||
oSql += " [STATUS] = @STATUS, "
|
||||
oSql += " [TITLE] = @TITLE, "
|
||||
oSql += " [ENVELOPE_TYPE] = @ENVELOPE_TYPE, "
|
||||
oSql += " [CONTRACT_TYPE] = @CONTRACT_TYPE, "
|
||||
oSql += " [CHANGED_WHEN] = GETDATE() "
|
||||
oSql += " [LANGUAGE] = @LANGUAGE, "
|
||||
oSql += " [CERTIFICATION_TYPE] = @CERTIFICATION_TYPE, "
|
||||
oSql += " [EXPIRES_WHEN_DAYS] = @EXPIRES_WHEN_DAYS, "
|
||||
oSql += " [EXPIRES_WARNING_WHEN_DAYS] = @EXPIRES_WARNING_WHEN_DAYS, "
|
||||
oSql += " [FIRST_REMINDER_DAYS] = @FIRST_REMINDER_DAYS, "
|
||||
oSql += " [FINAL_EMAIL_TO_CREATOR] = @FINAL_EMAIL_TO_CREATOR, "
|
||||
oSql += " [FINAL_EMAIL_TO_RECEIVERS] = @FINAL_EMAIL_TO_RECEIVERS, "
|
||||
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 += " [TFA_Enabled] = @TFA_Enabled"
|
||||
oSql += " WHERE GUID = @ID AND USER_ID = @USER_ID"
|
||||
|
||||
|
||||
Dim oCommand As New SqlCommand(oSql)
|
||||
oCommand.Parameters.Add("SUBJECT", SqlDbType.NVarChar).Value = pEnvelope.Subject
|
||||
oCommand.Parameters.Add("ID", SqlDbType.Int).Value = pEnvelope.Id
|
||||
oCommand.Parameters.Add("USER_ID", SqlDbType.Int).Value = pEnvelope.UserId
|
||||
oCommand.Parameters.Add("MESSAGE", SqlDbType.NVarChar).Value = pEnvelope.Message
|
||||
oCommand.Parameters.Add("STATUS", SqlDbType.Int).Value = pEnvelope.Status
|
||||
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
|
||||
|
||||
oCommand.Parameters.Add("ID", SqlDbType.Int).Value = pEnvelope.Id
|
||||
oCommand.Parameters.Add("USER_ID", SqlDbType.Int).Value = pEnvelope.UserId
|
||||
|
||||
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
|
||||
oCommand.Parameters.Add("EXPIRES_WARNING_WHEN_DAYS", SqlDbType.Int).Value = pEnvelope.ExpiresWarningWhenDays
|
||||
oCommand.Parameters.Add("FIRST_REMINDER_DAYS", SqlDbType.Int).Value = pEnvelope.FirstReminderDays
|
||||
oCommand.Parameters.Add("FINAL_EMAIL_TO_CREATOR", SqlDbType.Int).Value = pEnvelope.FinalEmailToCreator
|
||||
oCommand.Parameters.Add("FINAL_EMAIL_TO_RECEIVERS", SqlDbType.Int).Value = pEnvelope.FinalEmailToReceivers
|
||||
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
|
||||
@@ -172,7 +226,7 @@ Public Class EnvelopeModel
|
||||
Public Function Delete(pEnvelope As Envelope, pTransaction As SqlTransaction) As Boolean
|
||||
Try
|
||||
Dim oSql = $"DELETE FROM [dbo].[TBSIG_ENVELOPE] WHERE GUID = {pEnvelope.Id}"
|
||||
'Return Database.ExecuteNonQuery(oSql, pTransaction)
|
||||
Return Database.ExecuteNonQuery(oSql, pTransaction)
|
||||
|
||||
Catch ex As Exception
|
||||
Return False
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user