Compare commits
903 Commits
feature/te
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a441909408 | ||
|
|
a7bdbb5495 | ||
|
|
3c0b9d36d4 | ||
|
|
9ff3035730 | ||
|
|
c933793721 | ||
|
|
4746d50627 | ||
|
|
fdfdba550e | ||
|
|
09d53b7743 | ||
|
|
d691164af6 | ||
|
|
43f9db59d4 | ||
|
|
7669d27e7b | ||
|
|
d7d46d5429 | ||
|
|
205f9c678e | ||
|
|
cf5e235fc9 | ||
|
|
25eb72ee05 | ||
|
|
770a489f7f | ||
|
|
18c7875844 | ||
|
|
0838f30a24 | ||
|
|
15e7417766 | ||
|
|
ab112e85c1 | ||
|
|
2e3833f55d | ||
|
|
16364671d0 | ||
|
|
8054806cd3 | ||
|
|
d4396fe6d5 | ||
|
|
6d0354946a | ||
|
|
00b4ad800d | ||
|
|
34eb724170 | ||
|
|
1919b1b306 | ||
|
|
7dae6d81c5 | ||
|
|
2b27e39234 | ||
|
|
9718f8d3fd | ||
|
|
1a5ae41001 | ||
|
|
8ed5f3388b | ||
|
|
77483b6bd0 | ||
|
|
c32c2cdab0 | ||
|
|
fbb8a7b519 | ||
|
|
61e557712b | ||
|
|
c28076df68 | ||
|
|
032f6f87c9 | ||
|
|
cfac2bcc6b | ||
|
|
c420bda820 | ||
|
|
9fc3aef669 | ||
|
|
f55ebd9ecc | ||
|
|
a3a1ee67fc | ||
|
|
945e402639 | ||
|
|
3624a6e49a | ||
|
|
850e85ffdb | ||
|
|
6b885f3212 | ||
|
|
87ba79905c | ||
|
|
ae8aecc005 | ||
|
|
45c0c3d902 | ||
|
|
3610e6c76f | ||
|
|
7d07b1c882 | ||
|
|
abfc9eed95 | ||
|
|
d3e0d8f52c | ||
|
|
1967468fec | ||
|
|
569c24924a | ||
|
|
091a648a82 | ||
|
|
7a087764c1 | ||
|
|
5e60074d2f | ||
|
|
635925b3fc | ||
|
|
fad8fb3af2 | ||
|
|
b3b547914b | ||
|
|
556e6a4f6b | ||
|
|
14143c9356 | ||
|
|
34680a3972 | ||
|
|
6068c39c33 | ||
|
|
e0717e3466 | ||
|
|
bde5c88471 | ||
|
|
84c1d037c6 | ||
|
|
dba47d0f0f | ||
|
|
298ccff842 | ||
|
|
ab7f6a1470 | ||
|
|
bc1b6b9e6d | ||
|
|
5425e06399 | ||
|
|
5d0b26aca6 | ||
|
|
1d595eb1f0 | ||
|
|
a7db55cb13 | ||
|
|
d2fdba5658 | ||
|
|
d1883fc5b6 | ||
|
|
a875f94ca4 | ||
|
|
df65dac4cb | ||
|
|
9667144c9b | ||
|
|
8548dcaf66 | ||
|
|
52c5dbea1f | ||
|
|
65ccf32346 | ||
|
|
fac80bbc5c | ||
|
|
ad20597434 | ||
|
|
66809bb136 | ||
|
|
c7a74fed78 | ||
|
|
8a5e97b9ce | ||
|
|
08671583fe | ||
|
|
e7f3b47bb6 | ||
|
|
00b47d21dc | ||
|
|
ef86d1909d | ||
|
|
793444b96e | ||
|
|
11d97683d0 | ||
|
|
e3eff19de4 | ||
|
|
c65a62e9ac | ||
|
|
867f0a9c02 | ||
|
|
d55a72e57a | ||
|
|
f3fc2e2ce2 | ||
|
|
3507130e64 | ||
|
|
6a5792adf6 | ||
|
|
d0c79c87cf | ||
|
|
c95a5f027c | ||
|
|
4f289c359f | ||
|
|
4efc1b897a | ||
|
|
0584172bbd | ||
|
|
295839c048 | ||
|
|
5767e3465e | ||
|
|
6f6095990f | ||
|
|
f3032becf4 | ||
|
|
96a8575cb6 | ||
|
|
86ff048c6b | ||
|
|
0d3e3051ab | ||
|
|
0d7b57dd6a | ||
|
|
15f05624ca | ||
|
|
47052745c7 | ||
|
|
83668117da | ||
|
|
63c72bc613 | ||
|
|
4453eab3bf | ||
|
|
e700f8b785 | ||
|
|
4adebda2ab | ||
|
|
bdaac65afe | ||
|
|
9956348a06 | ||
|
|
0e08794271 | ||
|
|
10f69631b0 | ||
|
|
d3f0d1bc87 | ||
|
|
f2c41d5191 | ||
|
|
28c97b446c | ||
|
|
b461f95638 | ||
|
|
969004b542 | ||
|
|
ce27ac8d17 | ||
|
|
b04bad6057 | ||
|
|
5f98b16bc1 | ||
|
|
71f4a78a16 | ||
|
|
f9a5b5aa01 | ||
|
|
efbfd26363 | ||
|
|
46cab2786a | ||
|
|
17b90b1b67 | ||
|
|
59933f4a88 | ||
|
|
d36cf3c7f2 | ||
|
|
861f1e559f | ||
|
|
9b74db96ba | ||
|
|
684dc3418d | ||
|
|
b3bc7bb0ac | ||
|
|
03d4f04b15 | ||
|
|
95f1ea4a00 | ||
|
|
5bbcfdffc0 | ||
|
|
5409b432d6 | ||
|
|
292c92c827 | ||
|
|
9ce067bd80 | ||
|
|
5210b8ec40 | ||
|
|
15ca9ade53 | ||
|
|
8b1f63bf45 | ||
|
|
c9b8be9405 | ||
|
|
af234311e6 | ||
|
|
e5ea667ea1 | ||
|
|
7ff7222072 | ||
|
|
d8b1a32783 | ||
|
|
3315a679a8 | ||
|
|
013d61b0d0 | ||
|
|
afe793a523 | ||
|
|
23078c0b66 | ||
|
|
c1fafaee6e | ||
|
|
fa0e29095f | ||
|
|
c7a9c2ff11 | ||
|
|
3be9566a2e | ||
|
|
b62a9b9ae6 | ||
|
|
f08a2d512a | ||
|
|
95cd4edebb | ||
|
|
21b184d97a | ||
|
|
e393d70186 | ||
|
|
511f392203 | ||
|
|
072c965593 | ||
|
|
65041c2b7a | ||
|
|
a5004c6d26 | ||
|
|
58d11fc7b9 | ||
|
|
8e40b77c70 | ||
|
|
4a32f55b61 | ||
|
|
12136e0fdc | ||
|
|
2bb20ef7fa | ||
|
|
2e83a72f29 | ||
|
|
19d7670ada | ||
|
|
8c7e64ffad | ||
|
|
edd6b87566 | ||
|
|
b21e34ec84 | ||
|
|
215afe0834 | ||
|
|
70d55ac6c3 | ||
|
|
39e78cb033 | ||
|
|
d4da6befb4 | ||
|
|
d4448fa798 | ||
|
|
0f72b876d0 | ||
|
|
ff603599b9 | ||
|
|
2aa354dd3a | ||
|
|
a1a7f4f568 | ||
|
|
bf69b806de | ||
|
|
9cabeef5d5 | ||
|
|
4eff4803c6 | ||
|
|
81cee51661 | ||
|
|
357743e1d6 | ||
|
|
0afb6ca4f2 | ||
|
|
0fc9d40155 | ||
|
|
d61eee0a93 | ||
|
|
5563c19dca | ||
|
|
491c57667b | ||
|
|
a1de121109 | ||
|
|
894be159f5 | ||
|
|
7e78063a0b | ||
|
|
6ea68ccef4 | ||
|
|
632cfdb5f6 | ||
|
|
e37bdaabdb | ||
|
|
aa5ff0daf1 | ||
|
|
ee687e42b5 | ||
|
|
a599021b31 | ||
|
|
4d36a3d813 | ||
|
|
b8710d57b3 | ||
|
|
bb5e7f5be7 | ||
|
|
01ab05b52e | ||
|
|
0761ef6676 | ||
|
|
f9183054f3 | ||
|
|
31c3ce45f0 | ||
|
|
939ebe426b | ||
|
|
f01ea9f6da | ||
|
|
25cc17bf09 | ||
|
|
1f60256117 | ||
|
|
584473565f | ||
|
|
508ac2d677 | ||
|
|
bb9bdabbae | ||
|
|
f6caa94136 | ||
|
|
43d37b67b3 | ||
|
|
92aa781a8f | ||
|
|
f23548adcf | ||
|
|
c21a97420d | ||
|
|
48a7d05ba1 | ||
|
|
1b8b828f3d | ||
|
|
1e552d22c0 | ||
|
|
227dd092b4 | ||
|
|
a36fcff7b6 | ||
|
|
b30531f552 | ||
|
|
c99f90546c | ||
|
|
0a8ed5d2c8 | ||
|
|
2d68469d8d | ||
|
|
ade8e7ed9d | ||
|
|
51b5201677 | ||
|
|
1664820a82 | ||
|
|
f2df7fe783 | ||
|
|
48a0637fba | ||
|
|
fa83069ff0 | ||
|
|
22a7f2c3af | ||
|
|
3df86ade4a | ||
|
|
a23aa12527 | ||
|
|
dddc608c34 | ||
|
|
b174ca57b1 | ||
|
|
1fe8170ec0 | ||
|
|
bbd8d5be9b | ||
|
|
258d26ede0 | ||
|
|
437941fc6c | ||
|
|
bb40b3fa20 | ||
|
|
34346b149b | ||
|
|
0f8e78a1aa | ||
|
|
4c5f164f2e | ||
|
|
a2e1b4367a | ||
|
|
b574df51bf | ||
|
|
bc057e73de | ||
|
|
13fd797148 | ||
|
|
ca75ee9607 | ||
|
|
0f651d6a67 | ||
|
|
f69921fe59 | ||
|
|
88c5e43e51 | ||
|
|
34c1c4f51c | ||
|
|
de0d4294ea | ||
|
|
3ccbac4b0e | ||
|
|
cdde8a7da6 | ||
|
|
ccbf977e01 | ||
|
|
9a99398961 | ||
|
|
f86c925835 | ||
|
|
d26d24271a | ||
|
|
0ad3973d23 | ||
|
|
3fe009512f | ||
|
|
f3823a9acd | ||
|
|
e3e3d5bc58 | ||
|
|
60e042587e | ||
|
|
9c4804d239 | ||
|
|
f5f9247834 | ||
|
|
9203993d6e | ||
|
|
260851661b | ||
|
|
0ce2b1644c | ||
|
|
5e215c2649 | ||
|
|
53bb752002 | ||
|
|
ffca299cb4 | ||
|
|
a65e9e1086 | ||
|
|
abda71fca3 | ||
|
|
c52dfbdf5a | ||
|
|
fef66f92b2 | ||
|
|
cdbf69abbf | ||
|
|
e5bac8f964 | ||
|
|
06f5f4f241 | ||
|
|
82661dcaf2 | ||
|
|
0ed4759266 | ||
|
|
15be976352 | ||
|
|
9b07def91d | ||
|
|
ec10bbdf8b | ||
|
|
b184217099 | ||
|
|
71a895f3a2 | ||
|
|
ac41a902a1 | ||
|
|
4397cddcc1 | ||
|
|
a557f0ab25 | ||
|
|
7d52b4b0a0 | ||
|
|
d794245409 | ||
|
|
dbe7949a1c | ||
|
|
4c79b8c2f4 | ||
|
|
2ac82ab8e7 | ||
|
|
44419f2c6c | ||
|
|
7a13b6adc2 | ||
|
|
45e67b8796 | ||
|
|
87eeddded3 | ||
|
|
e213127b25 | ||
|
|
adab452380 | ||
|
|
f7612ac89f | ||
|
|
8d33f19453 | ||
|
|
5d704e08f9 | ||
|
|
7ea1a87567 | ||
|
|
1c56c4665e | ||
|
|
50831dabfa | ||
|
|
dc42fcad40 | ||
|
|
0bc8bac5d3 | ||
|
|
0a09725ebe | ||
|
|
bea853cbf2 | ||
|
|
88ae52dd52 | ||
|
|
77c2f9b9a7 | ||
|
|
876ee17469 | ||
|
|
36eed8d0a1 | ||
|
|
0f935fcba3 | ||
|
|
a57aedf52c | ||
|
|
63129d7727 | ||
|
|
82da9860ce | ||
|
|
25a8bb0610 | ||
|
|
47ce4fab61 | ||
|
|
09a060e1a7 | ||
|
|
68937f298b | ||
|
|
c6110a6d65 | ||
|
|
62719aec6f | ||
|
|
a96372e542 | ||
|
|
3a113207d8 | ||
|
|
cbce87430f | ||
|
|
7ce90c1986 | ||
|
|
318883981e | ||
|
|
e08690f7ee | ||
|
|
1abcd56e97 | ||
|
|
1de9d75883 | ||
|
|
80cbda22bf | ||
|
|
256a50775d | ||
|
|
635dc05bde | ||
|
|
979e6a6650 | ||
|
|
361f899c70 | ||
|
|
04def902cd | ||
|
|
156337b82c | ||
|
|
a5dea2acf1 | ||
|
|
366b737e11 | ||
|
|
874fdc85ee | ||
|
|
d144b31747 | ||
|
|
5e7627862e | ||
|
|
e379e9b636 | ||
|
|
44f5a45887 | ||
|
|
9143292e0f | ||
|
|
7dc6a56902 | ||
|
|
48eadc410d | ||
|
|
bf5a2dd6f6 | ||
|
|
d7ea4214ed | ||
|
|
38a6ca6a82 | ||
|
|
d7694b37a2 | ||
|
|
32e0436f9e | ||
|
|
84d2a6fac0 | ||
|
|
c03b489650 | ||
|
|
05676c7fa2 | ||
|
|
8831a9b24e | ||
|
|
e37947fb7a | ||
|
|
99b6310d60 | ||
|
|
60371fb34b | ||
|
|
0d4c005862 | ||
|
|
149ce5144d | ||
|
|
9c0c442eb6 | ||
|
|
e5271c928e | ||
|
|
dd0096a04c | ||
|
|
52bd1dea3c | ||
|
|
11088ddfef | ||
|
|
342257a9c6 | ||
|
|
8e2bf84a9d | ||
|
|
4349fdc152 | ||
|
|
6957857b42 | ||
|
|
3d9b7fc03f | ||
|
|
ff04d2a5ef | ||
|
|
4789a89257 | ||
|
|
c506aefdb4 | ||
|
|
3f9afa49e8 | ||
|
|
cfcff1f069 | ||
|
|
5188ab416e | ||
|
|
a42e24d7f4 | ||
|
|
65c6cdb3c9 | ||
|
|
78e0859c02 | ||
|
|
0cc48f8dfd | ||
|
|
f1b1f270d6 | ||
|
|
5fdb7d3773 | ||
|
|
a8af78c501 | ||
|
|
84ebccfe79 | ||
|
|
2ad5232e41 | ||
|
|
daf6f835c1 | ||
|
|
1377394d6a | ||
|
|
98bd00a89c | ||
|
|
06f7e57a74 | ||
|
|
8683480c40 | ||
|
|
33cec84890 | ||
|
|
6feb0d2a58 | ||
|
|
7a209664cb | ||
|
|
22bf27dd73 | ||
|
|
bb4af4c1ce | ||
|
|
a99b2e8165 | ||
|
|
2908477ce8 | ||
|
|
b977a2e46e | ||
|
|
9eb3ef0181 | ||
|
|
a377270141 | ||
|
|
5e8d8ea6f6 | ||
|
|
5494d92f39 | ||
|
|
1edbf8ae56 | ||
|
|
3adb35bec4 | ||
|
|
2697f014e6 | ||
|
|
1ac9f7ebcf | ||
|
|
7a9bffa3c5 | ||
|
|
fd910bf189 | ||
|
|
963cf0137b | ||
|
|
1037178711 | ||
|
|
a3d15f59c1 | ||
|
|
555dd3330a | ||
|
|
9caa1f3068 | ||
|
|
1f5c9f12ff | ||
|
|
833b391f47 | ||
|
|
630cde1f8f | ||
|
|
b6b6fad242 | ||
|
|
1253d7d0b4 | ||
|
|
c57e4c507e | ||
|
|
7eea40cc6c | ||
|
|
c2ed3eeff9 | ||
|
|
4beb6e0647 | ||
|
|
ef98112871 | ||
|
|
6d1b1ca31b | ||
|
|
4eeee75f33 | ||
|
|
2a0d9ce3f9 | ||
|
|
9bcf2d177e | ||
|
|
53c624c2c9 | ||
|
|
b8f64a1c86 | ||
|
|
2c2347f5f0 | ||
|
|
91e317057d | ||
|
|
399ad6e4a1 | ||
|
|
829dc2f4b3 | ||
|
|
804ad3cf88 | ||
|
|
2b7be87985 | ||
|
|
9c539ffd21 | ||
|
|
e4ec187c2f | ||
|
|
8dd9a73694 | ||
|
|
495ed75fc3 | ||
|
|
dc8abbba58 | ||
|
|
13b92135ae | ||
|
|
fd8da20e72 | ||
|
|
6d428cd15c | ||
|
|
3c32201e94 | ||
|
|
48ce264967 | ||
|
|
c6faa877a1 | ||
|
|
b1549ba775 | ||
|
|
9be0fad408 | ||
|
|
b24dcdaa86 | ||
|
|
00f1b8e495 | ||
|
|
96eef1a7a2 | ||
|
|
79fec2e9c9 | ||
|
|
8c96f75d3a | ||
|
|
675e9e0c42 | ||
|
|
cff6826424 | ||
|
|
535f9ce8da | ||
|
|
034c880e4f | ||
|
|
8198d6cfaa | ||
|
|
c80008cbb3 | ||
|
|
4016a26c2c | ||
|
|
3af71f2760 | ||
|
|
2361d483f0 | ||
|
|
ff4b3369c9 | ||
|
|
043d9ca299 | ||
|
|
4351f67d16 | ||
|
|
5f2b851efb | ||
|
|
f4a7a9a25e | ||
|
|
514cae7fe5 | ||
|
|
39ac84566a | ||
|
|
f1058caeed | ||
|
|
dfc1f6016c | ||
|
|
81099adf64 | ||
|
|
47e8bee9db | ||
|
|
c9e3a9d086 | ||
|
|
801dc52cd2 | ||
|
|
cc969350f8 | ||
|
|
a94e4a6caf | ||
|
|
b72e432741 | ||
|
|
b1fb547b0e | ||
|
|
fdf3fe5b4f | ||
|
|
f5b26deb4c | ||
|
|
b7e88e4ec1 | ||
|
|
e7ae91af47 | ||
|
|
f760598d8f | ||
|
|
13dbd04084 | ||
|
|
6a918bf939 | ||
|
|
0f15e68623 | ||
|
|
66f1a86c77 | ||
|
|
09749e8344 | ||
|
|
2916c19cb1 | ||
|
|
3a463e1ed1 | ||
|
|
cd899b2774 | ||
|
|
e73a4cb8a3 | ||
|
|
b7c8c2b668 | ||
|
|
844ceb66c1 | ||
|
|
32aa88f6b4 | ||
|
|
1fcd3ecd6b | ||
|
|
6e2c2dfbdc | ||
|
|
8b746a5db5 | ||
|
|
193dfaca67 | ||
|
|
784b67ee5a | ||
|
|
f72ca45689 | ||
|
|
0c4ebbd6b9 | ||
|
|
bbaaa6f952 | ||
|
|
7245f71acb | ||
|
|
b6c8ec2f7c | ||
|
|
fe3b437b80 | ||
|
|
2f35d2b218 | ||
|
|
2af5e9fea7 | ||
|
|
e120ff589b | ||
|
|
aa1f3e0a8b | ||
|
|
8ef1c7187d | ||
|
|
15ab5d4215 | ||
|
|
20f760b37c | ||
|
|
8006a4c374 | ||
|
|
3430288026 | ||
|
|
5cf4c034eb | ||
|
|
8d340057a4 | ||
|
|
f266582f48 | ||
|
|
a8ead5bea4 | ||
|
|
5f0e4b381c | ||
|
|
31c2b596be | ||
|
|
5cfb45d3d2 | ||
|
|
14da82e2b7 | ||
|
|
552d760ead | ||
|
|
55c6b7419d | ||
|
|
b83207f715 | ||
|
|
99c7ef2529 | ||
|
|
89446913b1 | ||
|
|
e44646234e | ||
|
|
30c982f2c8 | ||
|
|
7539aa4510 | ||
|
|
c9389e04fa | ||
|
|
6f5174cc4b | ||
|
|
1a156e0b76 | ||
|
|
0f3434bca1 | ||
|
|
b5405370f4 | ||
|
|
e644afb8e6 | ||
|
|
cb93273528 | ||
|
|
67e42dc4e0 | ||
|
|
84ef6e6f4c | ||
|
|
4a56bbc07f | ||
|
|
562e9d0761 | ||
|
|
3fefb8efab | ||
|
|
57871d11c9 | ||
|
|
26cba53508 | ||
|
|
49fe599c35 | ||
|
|
71ffb03dfc | ||
|
|
bc760a6870 | ||
|
|
0bf85842c1 | ||
|
|
4fbea2e3e7 | ||
|
|
fd021041f7 | ||
|
|
a40962085c | ||
|
|
3d73c6f496 | ||
|
|
6cdd888967 | ||
|
|
e631281156 | ||
|
|
a0eee59ced | ||
|
|
531524be1e | ||
|
|
369cc6340a | ||
|
|
539da8d80e | ||
|
|
3ad5e0300c | ||
|
|
9d4a942a48 | ||
|
|
84fb04fb30 | ||
|
|
dc20d2c2c8 | ||
|
|
52c564b5e3 | ||
|
|
62852d48df | ||
|
|
d8c5668a38 | ||
|
|
6157154378 | ||
|
|
1c896f72e1 | ||
|
|
db09744506 | ||
|
|
7326a387ca | ||
|
|
887e56b98e | ||
|
|
a8a9232c4c | ||
|
|
a8b7a835c0 | ||
|
|
bab96ba58d | ||
|
|
9f4edce48a | ||
|
|
6c857290b8 | ||
|
|
f12b5d8e98 | ||
|
|
740e88fd1b | ||
|
|
c4e682254b | ||
|
|
bbb2a1b464 | ||
|
|
cc9daf9180 | ||
|
|
41a8a3c32a | ||
|
|
361b11ca2b | ||
|
|
c3aaba45cc | ||
|
|
44bce39a2a | ||
|
|
7a24702c47 | ||
|
|
7a86b37c13 | ||
|
|
e0d00dcc48 | ||
|
|
c34af58aa0 | ||
|
|
c55aa9d206 | ||
|
|
6956e49f4a | ||
|
|
767f77f261 | ||
|
|
80be82e361 | ||
|
|
fed0caa8d2 | ||
|
|
c2c6438187 | ||
|
|
7e65396ffe | ||
|
|
18a8f5215f | ||
|
|
0cdd10e985 | ||
|
|
87cd0b06e1 | ||
|
|
23b437e60a | ||
|
|
9c48547c36 | ||
|
|
a4426e87ce | ||
|
|
94ecfbd1b4 | ||
|
|
71c81631f9 | ||
|
|
a05bbc9c7f | ||
|
|
649b8b6a46 | ||
|
|
4af3ada659 | ||
|
|
aafe9fa31a | ||
|
|
808ce8cbaf | ||
|
|
436368b5e6 | ||
|
|
07a0bacf55 | ||
|
|
a1b224adbd | ||
|
|
23929d2772 | ||
|
|
1a585e9fe3 | ||
|
|
5dd27f682b | ||
|
|
e382e4e833 | ||
|
|
4b61a19a95 | ||
|
|
fbf9320f6c | ||
|
|
46f9523b2c | ||
|
|
cdece93037 | ||
|
|
999ecafdf8 | ||
|
|
f77c08aac8 | ||
|
|
27d2208a72 | ||
|
|
856f09583a | ||
|
|
596a8dba31 | ||
|
|
5e5b8e54ca | ||
|
|
d6b95dad3e | ||
|
|
2b574b502e | ||
|
|
e5b23b2df7 | ||
|
|
dc96ff8439 | ||
|
|
111f79a1d8 | ||
|
|
08c8d65f3c | ||
|
|
81c21b1cbe | ||
|
|
ce6ec13b4c | ||
|
|
0d5d6a1c7a | ||
|
|
c28dcbfe40 | ||
|
|
11d050a92e | ||
|
|
0f782c802d | ||
|
|
e00e5043c2 | ||
|
|
e94ff93c7d | ||
|
|
a58bfa2f54 | ||
|
|
00052b7a43 | ||
|
|
e8202a5dae | ||
|
|
0dd9d0ed07 | ||
|
|
057b6d805a | ||
|
|
c90606f4c0 | ||
|
|
63253581a3 | ||
|
|
a586ec0eeb | ||
|
|
9e1189726d | ||
|
|
65ca13089b | ||
|
|
4451c07f02 | ||
|
|
d0faf8a33d | ||
|
|
78e82020ab | ||
|
|
5baaa71933 | ||
|
|
16c3388ffe | ||
|
|
2ef9800eae | ||
|
|
4843f79466 | ||
|
|
a6c6a4111c | ||
|
|
abccf8ca82 | ||
|
|
26d03e6b6f | ||
|
|
c67fa5926b | ||
|
|
0f203d39a4 | ||
|
|
dae360a7ac | ||
|
|
64f519f100 | ||
|
|
e377df12a0 | ||
|
|
62c81c3654 | ||
|
|
a4683a4eed | ||
|
|
f9090cfa3f | ||
|
|
398ec390b7 | ||
|
|
b52ac441e9 | ||
|
|
b08a666022 | ||
|
|
088a4ac21b | ||
|
|
06b3d236c8 | ||
|
|
a18f9d11b8 | ||
|
|
fb133a4770 | ||
|
|
bb9e977e78 | ||
|
|
581206bd16 | ||
|
|
46123e179d | ||
|
|
6a4047effb | ||
|
|
01747eab4f | ||
|
|
4b6cfbb66d | ||
|
|
e4a5e6efb7 | ||
|
|
cf124d1326 | ||
|
|
fe777da0f5 | ||
|
|
b66e436058 | ||
|
|
1622228613 | ||
|
|
a5866b36c8 | ||
|
|
efd777acd8 | ||
|
|
05faad96bc | ||
|
|
cfda6a8217 | ||
|
|
f4bdff1901 | ||
|
|
55922a85e8 | ||
|
|
f3758fb003 | ||
|
|
00a1cadb83 | ||
|
|
fac9544864 | ||
|
|
5d480887a2 | ||
|
|
3e205d0b1b | ||
|
|
adb6332bf5 | ||
|
|
23cf4cf5e9 | ||
|
|
2ae40e6403 | ||
|
|
1a4d97a14f | ||
|
|
d921c3f6a0 | ||
|
|
9079ae18af | ||
|
|
9e70d9e199 | ||
|
|
6412f58d58 | ||
|
|
c2d02b3faa | ||
|
|
aabfd5d8b5 | ||
|
|
1387065784 | ||
|
|
afa61062e4 | ||
|
|
efdf6a8868 | ||
|
|
a71ee404ed | ||
|
|
8485a6b48a | ||
|
|
f0160df8d1 | ||
|
|
f962037aaa | ||
|
|
2a4c8c2b19 | ||
|
|
d24ab46616 | ||
|
|
e723550b53 | ||
|
|
8f4f95b166 | ||
|
|
e9ba3c8da1 | ||
|
|
84d033ff54 | ||
|
|
1f6339f71d | ||
|
|
64a7d24639 | ||
|
|
2c604b1aa3 | ||
|
|
7d875ee7eb | ||
|
|
edb333aa29 | ||
|
|
38d3832732 | ||
|
|
0408e3986e | ||
|
|
1a0cea1332 | ||
|
|
05153504d3 | ||
|
|
5da98461f0 | ||
|
|
f5c2a115f4 | ||
|
|
08c6f11e88 | ||
|
|
03dc5f2d50 | ||
|
|
32411a668f | ||
|
|
20ca0cd798 | ||
|
|
4f1c926a17 | ||
|
|
6110dd1497 | ||
|
|
63dbc073c7 | ||
|
|
926e8b6b6b | ||
|
|
31165bd8f6 | ||
|
|
6b2fa6b9b6 | ||
|
|
141bf035ad | ||
|
|
8c3d2266ba | ||
|
|
c1dda3cd26 | ||
|
|
a300f61609 | ||
|
|
4935d81b0c | ||
|
|
a655100ec4 | ||
|
|
1e64903352 | ||
|
|
16a31bfb65 | ||
|
|
24e3771b08 | ||
|
|
8d2091edc4 | ||
|
|
7998b81bb6 | ||
|
|
4763e6db89 | ||
|
|
6280e342eb | ||
|
|
83d6ef71ef | ||
|
|
9ac1545fe8 | ||
|
|
59c1401053 | ||
|
|
033493aaee | ||
|
|
7acc0889b7 | ||
|
|
01ca31fbbf | ||
|
|
4a6777be71 | ||
|
|
7c37c16be7 | ||
|
|
d5494660bc | ||
|
|
2aff32f33e | ||
|
|
3a93c1f715 | ||
|
|
1adf46179e | ||
|
|
bf10c3baf0 | ||
|
|
1d47744b30 | ||
|
|
dcb5c0e03e | ||
|
|
b11c95dd39 | ||
|
|
6b82815b7a | ||
|
|
ef18d68102 | ||
|
|
7f4a53ba5f | ||
|
|
5a526484d6 | ||
|
|
fac8a1ac85 | ||
|
|
11dcb2fb93 | ||
|
|
c8244781b4 | ||
|
|
a086a71833 | ||
|
|
e510f07be9 | ||
|
|
e00ea01803 | ||
|
|
a86be93177 | ||
|
|
f23f66f0ed | ||
|
|
04759967e2 | ||
|
|
8756eea0e0 | ||
|
|
77db059a2e | ||
|
|
b002f7d544 | ||
|
|
92cc2895ad | ||
|
|
cfeb370299 | ||
|
|
6d1d51098b | ||
|
|
ef7c470618 | ||
|
|
57cb10ba1d | ||
|
|
9a93c0b18b | ||
|
|
623068e1a1 | ||
|
|
f870759747 | ||
|
|
07b29d9c50 | ||
|
|
c9cda89e17 | ||
|
|
54bfdfafe2 | ||
|
|
c31a29cea2 | ||
|
|
6770d03ae1 | ||
|
|
1c60bc6586 | ||
|
|
ddcff217e5 | ||
|
|
c60c79ef06 | ||
|
|
a37ac83339 | ||
|
|
d7e5e16351 | ||
|
|
5bfeec1b21 | ||
|
|
7df02d588a | ||
|
|
29a274fdb0 | ||
|
|
6525e0c2bc | ||
|
|
88d63b46b9 | ||
|
|
9c8e584e5a | ||
|
|
147247cfe6 | ||
|
|
71f0756a3a | ||
|
|
910948bd2d | ||
|
|
d4baa5d8b7 | ||
|
|
1fc74f2a0c | ||
|
|
06e0bba76c | ||
|
|
72b148376e | ||
|
|
873daa2736 | ||
|
|
8e8aa645d0 | ||
|
|
f0c6b868e8 | ||
|
|
c9af40ddb6 | ||
|
|
729923fdea | ||
|
|
efc2b200ad | ||
|
|
75676c33b1 | ||
|
|
5f1731444e | ||
|
|
9ddcd56a67 | ||
|
|
3ab607ccbf | ||
|
|
d46ae2834a | ||
|
|
6601ee0188 | ||
|
|
45a0ca1800 | ||
|
|
8c4b177ef2 | ||
|
|
dec81549e0 | ||
|
|
ba8cf68779 | ||
|
|
7490402bb7 | ||
|
|
a5e3c0c98a | ||
|
|
ed052fa741 | ||
|
|
8a4c754250 | ||
|
|
da6856f31d | ||
|
|
b2cf55b5cc | ||
|
|
3fde378ade | ||
|
|
8f4a03dd08 | ||
|
|
857f2383d2 | ||
|
|
f3ef80df06 | ||
|
|
06360c5cbd | ||
|
|
9110e68266 | ||
|
|
36e8a2bfdb | ||
|
|
f2a6a90529 | ||
|
|
5b4f194cad | ||
|
|
43e85af0e9 | ||
|
|
6654dc9546 | ||
|
|
7a9d90a76c | ||
|
|
c78a4c1186 | ||
|
|
9eb0e5e8df | ||
|
|
eab0b3de39 | ||
|
|
8ae5ea89c6 | ||
|
|
71f760c1e4 | ||
|
|
93d2b77ca5 | ||
|
|
06970a1477 | ||
|
|
8c8a088cc8 | ||
|
|
f8645ef50c | ||
|
|
f5f33978ed | ||
|
|
d845b4cef2 | ||
|
|
baeadd145e | ||
|
|
82ed6b0b05 | ||
|
|
c2110cd965 | ||
|
|
dff30d5f7d | ||
|
|
042f3a079c | ||
|
|
c42983aa91 | ||
|
|
333fd40449 | ||
|
|
a98cc0a6f2 | ||
|
|
6bb3c93b84 | ||
|
|
01f857fcef | ||
|
|
96be1ba52e | ||
|
|
81b66236f9 | ||
|
|
7b6af5bf3b | ||
|
|
a37b2dbc32 | ||
|
|
47a9bc0343 | ||
|
|
d849859def | ||
|
|
3c4c93a634 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -33,4 +33,4 @@ gradlew.bat
|
||||
gradle/
|
||||
|
||||
**/.gradle
|
||||
**/build
|
||||
**/build
|
||||
|
||||
@ -11,7 +11,7 @@ deploy:
|
||||
- dind
|
||||
script:
|
||||
- echo "Building with gradle version ${BUILDVERSION}"
|
||||
- gradle -Pversion=${BUILDVERSION} publish
|
||||
- gradle -Pversion=${BUILDVERSION} publish
|
||||
- gradle bootBuildImage --publishImage -PbuildbootDockerHostNetwork=true -Pversion=${BUILDVERSION}
|
||||
- echo "BUILDVERSION=$BUILDVERSION" >> version.env
|
||||
artifacts:
|
||||
@ -20,4 +20,5 @@ deploy:
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
- if: $CI_COMMIT_BRANCH =~ /^release/
|
||||
- if: $CI_COMMIT_BRANCH =~ /^feature/
|
||||
- if: $CI_COMMIT_TAG
|
||||
57
README.md
Normal file
57
README.md
Normal file
@ -0,0 +1,57 @@
|
||||

|
||||
## Description
|
||||
*TODO*
|
||||
|
||||
## Table of Contents
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
- [License](#license)
|
||||
- [Tests](#tests)
|
||||
- [API](#api)
|
||||
## Installation
|
||||
*TODO*
|
||||
|
||||
## Usage
|
||||
*TODO*
|
||||
|
||||
## License
|
||||
<br />
|
||||
This application is covered by the proprietary knecon license.
|
||||
|
||||
## Tests
|
||||
*TODO*
|
||||
|
||||
## API
|
||||
|
||||
### Files
|
||||
|
||||
The OpenAPI specifications for RedactManager and Documine are located here:<br> `./persistence-service-v1/persistence-service-external-api-v2/src/main/resources/api`
|
||||
|
||||
The Redocly configuration file `redocly.yaml` is located in the root directory of the project. It contains the settings for linting the specifications and generating the API documentation. If you run the redocly commands from there, you do not need to specify the path to the configuration file.
|
||||
|
||||
The Redocly files are located in the `redocly` directory:
|
||||
* The `templates` directory contains the [Handlebars](https://handlebarsjs.com/) templates for RedactManager and Documine, respectively.
|
||||
* The `build` directory is the default output directory for the generated API documentation.
|
||||
|
||||
### Redocly Installation
|
||||
Execute the following command to install the Redocly CLI.
|
||||
```bash
|
||||
npm install -g @redocly/cli@latest
|
||||
```
|
||||
|
||||
### Redocly Linting
|
||||
Execute the following commands in the root directory of the project to lint the OpenAPI specifications.
|
||||
|
||||
Please refer to the Redocly documentation for detailed information on the linting rules.
|
||||
|
||||
```bash
|
||||
redocly lint redactmanager
|
||||
redocly lint documine
|
||||
```
|
||||
|
||||
### Redocly Docs Generation
|
||||
Execute the following commands in the root directory of the project to generate the API documentation.
|
||||
```bash
|
||||
redocly build-docs redactmanager --output ./redocly/build/redactmanager.html
|
||||
redocly build-docs documine --output ./redocly/build/documine.html
|
||||
```
|
||||
@ -6,10 +6,11 @@ plugins {
|
||||
jacoco
|
||||
}
|
||||
|
||||
val redactionServiceVersion by rootProject.extra { "4.246.0" }
|
||||
val pdftronRedactionServiceVersion by rootProject.extra { "4.48.0" }
|
||||
val redactionReportServiceVersion by rootProject.extra { "4.47.0" }
|
||||
val searchServiceVersion by rootProject.extra { "2.71.0" }
|
||||
val redactionServiceVersion by rootProject.extra { "4.290.0" }
|
||||
val pdftronRedactionServiceVersion by rootProject.extra { "4.90.0-RED10115.0" }
|
||||
val redactionReportServiceVersion by rootProject.extra { "4.81.0" }
|
||||
val searchServiceVersion by rootProject.extra { "2.90.0" }
|
||||
val documentVersion by rootProject.extra { "4.433.0" }
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
@ -45,6 +46,8 @@ tasks.named<Test>("test") {
|
||||
reports {
|
||||
junitXml.outputLocation.set(layout.buildDirectory.dir("reports/junit"))
|
||||
}
|
||||
minHeapSize = "512m"
|
||||
maxHeapSize = "2048m"
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
@ -65,20 +68,12 @@ java {
|
||||
}
|
||||
|
||||
allprojects {
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>(name) {
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://nexus.knecon.com/repository/red-platform-releases/")
|
||||
credentials {
|
||||
username = providers.gradleProperty("mavenUser").getOrNull();
|
||||
password = providers.gradleProperty("mavenPassword").getOrNull();
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Javadoc> {
|
||||
options {
|
||||
this as StandardJavadocDocletOptions
|
||||
addBooleanOption("Xdoclint:none", true)
|
||||
addStringOption("Xmaxwarns", "1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
plugins {
|
||||
id("com.iqser.red.service.java-conventions")
|
||||
id("io.spring.dependency-management") version "1.1.3"
|
||||
id("io.spring.dependency-management") version "1.1.6"
|
||||
id("org.sonarqube") version "4.4.1.3373"
|
||||
id("io.freefair.lombok") version "8.4"
|
||||
id("io.freefair.lombok") version "8.6"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@ -9,11 +9,17 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.ApplicationConfigurationEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.ApplicationConfigurationResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.Builder;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -23,14 +29,24 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class ApplicationConfigurationController implements ApplicationConfigurationResource {
|
||||
|
||||
private final ApplicationConfigService applicationConfigService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_APP_CONFIG + "')")
|
||||
public ApplicationConfig createOrUpdateAppConfig(@Valid @RequestBody ApplicationConfig appConfig) {
|
||||
|
||||
return MagicConverter.convert(applicationConfigService.saveApplicationConfiguration(MagicConverter.convert(appConfig, ApplicationConfigurationEntity.class)),
|
||||
var result = MagicConverter.convert(applicationConfigService.saveApplicationConfiguration(convert(appConfig)),
|
||||
ApplicationConfig.class);
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId("ApplicationConfig")
|
||||
.category(AuditCategory.SETTINGS.name())
|
||||
.message("Application config has been changed.")
|
||||
.build());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -41,4 +57,18 @@ public class ApplicationConfigurationController implements ApplicationConfigurat
|
||||
return MagicConverter.convert(applicationConfigService.getApplicationConfig(), ApplicationConfig.class);
|
||||
}
|
||||
|
||||
|
||||
private ApplicationConfigurationEntity convert(ApplicationConfig appConfig){
|
||||
var entity = ApplicationConfigurationEntity.builder()
|
||||
.downloadCleanupDownloadFilesHours(appConfig.getDownloadCleanupDownloadFilesHours())
|
||||
.downloadCleanupNotDownloadFilesHours(appConfig.getDownloadCleanupNotDownloadFilesHours())
|
||||
.softDeleteCleanupTime(appConfig.getSoftDeleteCleanupTime())
|
||||
.build();
|
||||
|
||||
if(appConfig.getHardDeleteCleanupRetryTime() != null){
|
||||
entity.setHardDeleteCleanupRetryTime(appConfig.getHardDeleteCleanupRetryTime());
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,187 +0,0 @@
|
||||
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_RSS;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_REDACTION_LOG;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentLogService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentOverrideService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.ComponentLogResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentsOverrides;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class ComponentLogController implements ComponentLogResource {
|
||||
|
||||
ComponentLogService componentLogService;
|
||||
ComponentOverrideService componentOverrideService;
|
||||
AuditPersistenceService auditPersistenceService;
|
||||
AccessControlService accessControlService;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public ComponentLog getComponentLog(String dossierId, String fileId, boolean includeOverrides) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndViewPermissionsToDossier(dossierId);
|
||||
accessControlService.validateFileResourceExistence(fileId);
|
||||
|
||||
return componentLogService.getComponentLog(dossierId, fileId, includeOverrides);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.validateFileResourceExistence(fileId);
|
||||
|
||||
if (componentsOverrides.getComponentOverrides() == null || componentsOverrides.getComponentOverrides().isEmpty()) {
|
||||
throw new BadRequestException("Request body cannot be empty!");
|
||||
}
|
||||
var componentLog = componentLogService.getComponentLog(dossierId, fileId);
|
||||
var allComponents = componentLog.getComponentLogEntries();
|
||||
|
||||
componentOverrideService.addOverrides(dossierId, fileId, componentsOverrides);
|
||||
|
||||
componentsOverrides.getComponentOverrides()
|
||||
.forEach((componentName, overrideValue) -> auditOverride(dossierId, fileId, componentName, overrideValue, allComponents));
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndViewPermissionsToDossier(dossierId);
|
||||
accessControlService.validateFileResourceExistence(fileId);
|
||||
return componentOverrideService.getOverrides(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.validateFileResourceExistence(fileId);
|
||||
|
||||
if (revertOverrideRequest.getComponents() == null || revertOverrideRequest.getComponents().isEmpty()) {
|
||||
throw new BadRequestException("Request body cannot be empty!");
|
||||
}
|
||||
var componentLog = componentLogService.getComponentLog(dossierId, fileId);
|
||||
var allComponents = componentLog.getComponentLogEntries();
|
||||
|
||||
componentOverrideService.revertOverrides(dossierId, fileId, revertOverrideRequest);
|
||||
|
||||
revertOverrideRequest.getComponents()
|
||||
.forEach(componentNameToRevert -> auditOverrideRevert(dossierId, fileId, componentNameToRevert, allComponents));
|
||||
}
|
||||
|
||||
|
||||
private void auditOverride(String dossierId, String fileId, String componentName, String overrideValue, List<ComponentLogEntry> allComponentLogEntries) {
|
||||
|
||||
Optional<ComponentLogEntry> component = allComponentLogEntries.stream()
|
||||
.filter(c -> c.getName().equals(componentName))
|
||||
.findFirst();
|
||||
String originalValue = getOriginalValue(component);
|
||||
String value = getValue(component);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("The component is overwritten with value")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
"ComponentName",
|
||||
componentName,
|
||||
"Action",
|
||||
"MODIFY",
|
||||
"OriginalValue",
|
||||
originalValue,
|
||||
"OldValue",
|
||||
value,
|
||||
"NewValue",
|
||||
overrideValue))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private void auditOverrideRevert(String dossierId, String fileId, String componentNameToRevert, List<ComponentLogEntry> allComponentLogEntries) {
|
||||
|
||||
Optional<ComponentLogEntry> component = allComponentLogEntries.stream()
|
||||
.filter(c -> c.getName().equals(componentNameToRevert))
|
||||
.findFirst();
|
||||
String originalValue = getOriginalValue(component);
|
||||
String value = getValue(component);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("The component override for was reverted")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
"ComponentName",
|
||||
componentNameToRevert,
|
||||
"Action",
|
||||
"REVERT",
|
||||
"OriginalValue",
|
||||
originalValue,
|
||||
"OldValue",
|
||||
value,
|
||||
"NewValue",
|
||||
originalValue))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private String getValue(Optional<ComponentLogEntry> component) {
|
||||
|
||||
return component.map(ComponentLogEntry::getComponentValues)
|
||||
.stream()
|
||||
.map(a -> a.stream()
|
||||
.map(ComponentLogEntryValue::getValue)
|
||||
.collect(Collectors.joining(", ")))
|
||||
.findFirst()
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
|
||||
private static String getOriginalValue(Optional<ComponentLogEntry> component) {
|
||||
|
||||
return component.map(ComponentLogEntry::getComponentValues)
|
||||
.stream()
|
||||
.map(a -> a.stream()
|
||||
.map(ComponentLogEntryValue::getOriginalValue)
|
||||
.collect(Collectors.joining(", ")))
|
||||
.findFirst()
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
}
|
||||
@ -11,8 +11,12 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.acl.custom.service.CustomPermissionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.CustomPermissionMappingResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.permission.CustomPermissionMappingModel;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@ -21,6 +25,7 @@ import lombok.RequiredArgsConstructor;
|
||||
public class CustomPermissionMappingController implements CustomPermissionMappingResource {
|
||||
|
||||
private final CustomPermissionService customPermissionService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -36,6 +41,14 @@ public class CustomPermissionMappingController implements CustomPermissionMappin
|
||||
public void saveCustomPermissionMappings(@PathVariable(TARGET_OBJECT_NAME) String targetObject, @RequestBody List<CustomPermissionMappingModel> customPermissionMappingModels) {
|
||||
|
||||
customPermissionService.saveCustomPermissionMappings(targetObject, customPermissionMappingModels);
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(targetObject)
|
||||
.category(AuditCategory.SETTINGS.name())
|
||||
.message("Custom permissions have been changed.")
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
@ -22,25 +23,28 @@ import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryDifferenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.TypeValueMapper;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.model.UpdateEntries;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.DictionaryResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.UpdateTypeValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dictionary.Dictionary;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dictionary.DictionaryDifferenceResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.Type;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import feign.FeignException;
|
||||
import jakarta.validation.Valid;
|
||||
@ -55,6 +59,7 @@ public class DictionaryController implements DictionaryResource {
|
||||
private final DictionaryService dictionaryService;
|
||||
private final AuditPersistenceService auditClient;
|
||||
private final AccessControlService accessControlService;
|
||||
private final DictionaryDifferenceService dictionaryDifferenceService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -106,6 +111,31 @@ public class DictionaryController implements DictionaryResource {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateEntries(String type, String dossierTemplateId, UpdateEntries updateEntries, String dossierId, DictionaryEntryType dictionaryEntryType) {
|
||||
|
||||
if (dossierId == null) {
|
||||
dictionaryService.updateGlobalEntries(type, dossierTemplateId, updateEntries.entriesToAdd(), updateEntries.entriesToDelete(), dictionaryEntryType);
|
||||
} else {
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
dictionaryService.updateDossierEntries(type, dossierTemplateId, updateEntries.entriesToAdd(), updateEntries.entriesToDelete(), dossierId, dictionaryEntryType);
|
||||
}
|
||||
|
||||
auditClient.insertRecord(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DICTIONARY.name())
|
||||
.message("Dictionary entries were updated.")
|
||||
.details(Map.of("Type",
|
||||
type,
|
||||
"Number of added entries",
|
||||
updateEntries.entriesToAdd() == null ? 0 : updateEntries.entriesToAdd().size(),
|
||||
"Number of deleted entries",
|
||||
updateEntries.entriesToDelete() == null ? 0 : updateEntries.entriesToDelete().size()))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void deleteEntries(@PathVariable(TYPE_PARAMETER_NAME) String type,
|
||||
@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@ -322,4 +352,29 @@ public class DictionaryController implements DictionaryResource {
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void changeFlags(@PathVariable(TYPE_PARAMETER_NAME) String type,
|
||||
@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@PathVariable(value = DOSSIER_ID_PARAMETER_NAME) String dossierId,
|
||||
@RequestParam(value = "addToDictionaryAction") boolean addToDictionaryAction) {
|
||||
|
||||
dictionaryService.changeAddToDictionary(type, dossierTemplateId, dossierId, addToDictionaryAction);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DictionaryDifferenceResponse getDictionaryDifference(String dossierTemplateId, Set<String> types) {
|
||||
|
||||
DictionaryDifferenceResponse dictionaryDifferenceResponse = dictionaryDifferenceService.calculatedDictionaryDifference(dossierTemplateId, types);
|
||||
auditClient.insertRecord(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DICTIONARY.name())
|
||||
.message("Dictionary differences was calculated.")
|
||||
.details(Map.of("DictionaryDifferenceResponse", dictionaryDifferenceResponse, "types", types))
|
||||
.build());
|
||||
return dictionaryDifferenceResponse;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.DossierAttributeConfigMapper;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierAttributeConfigEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
@ -52,7 +53,7 @@ public class DossierAttributesController implements DossierAttributesResource {
|
||||
var result = MagicConverter.convert(dossierAttributeConfigPersistenceService.setDossierAttributesConfig(dossierTemplateId,
|
||||
MagicConverter.convert(dossierAttributesConfig.getDossierAttributeConfigs(),
|
||||
DossierAttributeConfigEntity.class)),
|
||||
DossierAttributeConfig.class);
|
||||
DossierAttributeConfig.class, new DossierAttributeConfigMapper());
|
||||
auditPersistenceService.insertRecord(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
@ -72,7 +73,7 @@ public class DossierAttributesController implements DossierAttributesResource {
|
||||
var result = MagicConverter.convert(dossierAttributeConfigPersistenceService.addOrUpdateDossierAttribute(dossierTemplateId,
|
||||
MagicConverter.convert(dossierAttribute,
|
||||
DossierAttributeConfigEntity.class)),
|
||||
DossierAttributeConfig.class);
|
||||
DossierAttributeConfig.class, new DossierAttributeConfigMapper());
|
||||
auditPersistenceService.insertRecord(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
@ -118,7 +119,7 @@ public class DossierAttributesController implements DossierAttributesResource {
|
||||
public DossierAttributesConfig getDossierAttributesConfig(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId) {
|
||||
|
||||
var result = dossierAttributeConfigPersistenceService.getDossierAttributes(dossierTemplateId);
|
||||
return new DossierAttributesConfig(MagicConverter.convert(result, DossierAttributeConfig.class));
|
||||
return new DossierAttributesConfig(MagicConverter.convert(result, DossierAttributeConfig.class, new DossierAttributeConfigMapper()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@ import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -18,9 +20,15 @@ import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierAttributeEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.model.websocket.DossierEventType;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierCreatorService;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FilterByPermissionsService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeResponseV2;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.JsonNode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -41,7 +49,9 @@ import com.iqser.red.service.persistence.management.v1.processor.roles.Applicati
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.websocket.WebsocketService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierAttributePersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.users.model.User;
|
||||
@ -55,6 +65,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.Audit
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierAttributes;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.notification.NotificationType;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
@ -70,12 +81,15 @@ public class DossierController implements DossierResource {
|
||||
|
||||
private final DossierManagementService dossierManagementService;
|
||||
private final UserService userService;
|
||||
private final FilterByPermissionsService filterByPermissionsService;
|
||||
private final FileStatusManagementService fileStatusManagementService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
private final NotificationPersistenceService notificationPersistenceService;
|
||||
private final AccessControlService accessControlService;
|
||||
private final DossierACLService dossierACLService;
|
||||
private final DossierCreatorService dossierCreatorService;
|
||||
private final WebsocketService websocketService;
|
||||
private final DossierAttributePersistenceService dossierAttributePersistenceService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -98,6 +112,20 @@ public class DossierController implements DossierResource {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER + "')")
|
||||
public DossierChangeResponseV2 changesSinceV2(@RequestBody JSONPrimitive<OffsetDateTime> since) {
|
||||
|
||||
DossierChangeResponseV2 changes = dossierManagementService.changesSinceV2(since);
|
||||
|
||||
// filter only viewables
|
||||
changes.setFileChanges(filterByPermissionsService.onlyViewableHavingDossierId(changes.getFileChanges()));
|
||||
changes.setDossierChanges(filterByPermissionsService.onlyViewableHavingDossierId(changes.getDossierChanges()));
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + ADD_UPDATE_DOSSIER + "') && (#dossierRequest.dossierId == null || hasPermission(#dossierRequest.dossierId, 'Dossier', 'ACCESS_OBJECT') )")
|
||||
public ResponseEntity<Dossier> createDossierOrUpdateDossier(@RequestBody DossierRequest dossierRequest) {
|
||||
@ -217,6 +245,10 @@ public class DossierController implements DossierResource {
|
||||
.target(Map.of("dossierId", dossierRequest.getDossierId()))
|
||||
.build()));
|
||||
|
||||
websocketService.sendDossierEvent(dossierRequest.getDossierId(), DossierEventType.UPDATE);
|
||||
|
||||
updatedDossier.setDossierAttributes(convertDossierAttributes(dossierAttributePersistenceService.getDossierAttributes(updatedDossier.getId())));
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
||||
return new ResponseEntity<>(updatedDossier, httpHeaders, HttpStatus.OK);
|
||||
@ -231,6 +263,7 @@ public class DossierController implements DossierResource {
|
||||
.message("Dossier has been created.")
|
||||
.build());
|
||||
|
||||
websocketService.sendDossierEvent(created.getId(), DossierEventType.CREATE);
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
||||
return new ResponseEntity<>(created, httpHeaders, HttpStatus.CREATED);
|
||||
@ -336,6 +369,7 @@ public class DossierController implements DossierResource {
|
||||
.build(), members, approvers, ownerId);
|
||||
|
||||
dossierACLService.enhanceDossierWithACLData(newDossier);
|
||||
newDossier.setDossierAttributes(new DossierAttributes());
|
||||
|
||||
return newDossier;
|
||||
|
||||
@ -367,7 +401,8 @@ public class DossierController implements DossierResource {
|
||||
throw new AccessDeniedException("Can not delete dossier that is owned by a different user");
|
||||
}
|
||||
|
||||
dossierManagementService.delete(dossierId);
|
||||
|
||||
dossierManagementService.softDeleteDossier(dossierId);
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
@ -386,6 +421,29 @@ public class DossierController implements DossierResource {
|
||||
.target(Map.of("dossierId", dossierId, "dossierName", dossier.getDossierName()))
|
||||
.build()));
|
||||
|
||||
websocketService.sendDossierEvent(dossierId, DossierEventType.SOFT_DELETE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER + "')")
|
||||
public JSONPrimitive<Map<String, Dossier>> getDossiersByIds(@RequestBody JSONPrimitive<Set<String>> dossierIds) {
|
||||
|
||||
// filter dossiers based on view
|
||||
var viewableDossierIds = filterByPermissionsService.onlyViewableDossierIds(dossierIds.getValue());
|
||||
// load dossiers
|
||||
var dossiers = dossierManagementService.getDossiersByIds(viewableDossierIds);
|
||||
|
||||
// add attributes and ACL - already filtered before loading
|
||||
enhanceDossiersWithAttributeAndACLData(dossiers,false);
|
||||
|
||||
// build response
|
||||
var responseMap = new LinkedHashMap<String, Dossier>();
|
||||
for (var dossier : dossiers) {
|
||||
responseMap.put(dossier.getId(), dossier);
|
||||
}
|
||||
|
||||
return new JSONPrimitive<>(responseMap);
|
||||
}
|
||||
|
||||
|
||||
@ -395,67 +453,52 @@ public class DossierController implements DossierResource {
|
||||
@RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted) {
|
||||
|
||||
accessControlService.checkViewPermissionsToDossier(dossierId);
|
||||
|
||||
return dossierACLService.enhanceDossierWithACLData(dossierManagementService.getDossierById(dossierId, includeArchived, includeDeleted));
|
||||
var dossier = dossierManagementService.getDossierById(dossierId, includeArchived, includeDeleted);
|
||||
dossier.setDossierAttributes(convertDossierAttributes(dossierAttributePersistenceService.getDossierAttributes(dossierId)));
|
||||
return dossierACLService.enhanceDossierWithACLData(dossier);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER + "')")
|
||||
@PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')")
|
||||
public List<Dossier> getDossiers(@RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived,
|
||||
@RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted) {
|
||||
|
||||
return dossierManagementService.getAllDossiers(includeArchived, includeDeleted)
|
||||
.stream()
|
||||
.map(dossierACLService::enhanceDossierWithACLData)
|
||||
.collect(Collectors.toList());
|
||||
var dossiers = dossierManagementService.getAllDossiers(includeArchived, includeDeleted);
|
||||
return enhanceDossiersWithAttributeAndACLData(dossiers);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER + "')")
|
||||
@PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')")
|
||||
public List<Dossier> getDossiersForDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived,
|
||||
@RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted) {
|
||||
|
||||
return dossierManagementService.getAllDossiersForDossierTemplateId(dossierTemplateId, includeArchived, includeDeleted)
|
||||
.stream()
|
||||
.map(dossierACLService::enhanceDossierWithACLData)
|
||||
.collect(Collectors.toList());
|
||||
var dossiers = dossierManagementService.getAllDossiersForDossierTemplateId(dossierTemplateId, includeArchived, includeDeleted);
|
||||
return enhanceDossiersWithAttributeAndACLData(dossiers);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER + "')")
|
||||
@PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')")
|
||||
public List<Dossier> getSoftDeletedDossiers() {
|
||||
|
||||
return dossierManagementService.getSoftDeletedDossiers()
|
||||
.stream()
|
||||
.map(dossierACLService::enhanceDossierWithACLData)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
var dossiers = dossierManagementService.getSoftDeletedDossiers();
|
||||
return enhanceDossiersWithAttributeAndACLData(dossiers);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER + "')")
|
||||
@PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')")
|
||||
public List<Dossier> getArchivedDossiers() {
|
||||
|
||||
return dossierManagementService.getArchivedDossiers()
|
||||
.stream()
|
||||
.map(dossierACLService::enhanceDossierWithACLData)
|
||||
.collect(Collectors.toList());
|
||||
var dossiers = dossierManagementService.getArchivedDossiers();
|
||||
return enhanceDossiersWithAttributeAndACLData(dossiers);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER + "')")
|
||||
@PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')")
|
||||
public List<Dossier> getArchivedDossiersForDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
return dossierManagementService.getArchivedDossiersForDossierTemplateId(dossierTemplateId)
|
||||
.stream()
|
||||
.map(dossierACLService::enhanceDossierWithACLData)
|
||||
.collect(Collectors.toList());
|
||||
var dossiers = dossierManagementService.getArchivedDossiersForDossierTemplateId(dossierTemplateId);
|
||||
return enhanceDossiersWithAttributeAndACLData(dossiers);
|
||||
}
|
||||
|
||||
|
||||
@ -475,6 +518,7 @@ public class DossierController implements DossierResource {
|
||||
.category(AuditCategory.DOSSIER.name())
|
||||
.message("Dossier archived.")
|
||||
.build());
|
||||
websocketService.sendDossierEvent(dossierId, DossierEventType.ARCHIVE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,6 +536,7 @@ public class DossierController implements DossierResource {
|
||||
.category(AuditCategory.DOSSIER.name())
|
||||
.message("Dossier restored from archive.")
|
||||
.build());
|
||||
websocketService.sendDossierEvent(dossierId, DossierEventType.UNARCHIVE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -512,7 +557,7 @@ public class DossierController implements DossierResource {
|
||||
.category(AuditCategory.DOSSIER.name())
|
||||
.message("Dossier permanently deleted.")
|
||||
.build());
|
||||
|
||||
websocketService.sendDossierEvent(dossierId, DossierEventType.HARD_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,6 +577,7 @@ public class DossierController implements DossierResource {
|
||||
.category(AuditCategory.DOSSIER.name())
|
||||
.message("Dossier restored from trash.")
|
||||
.build());
|
||||
websocketService.sendDossierEvent(dossierId, DossierEventType.UNDELETE);
|
||||
|
||||
}
|
||||
}
|
||||
@ -547,5 +593,41 @@ public class DossierController implements DossierResource {
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
|
||||
private DossierAttributes convertDossierAttributes(List<DossierAttributeEntity> dossierAttributeEntities) {
|
||||
|
||||
Map<String, String> attributeIdToValue = new HashMap<>();
|
||||
for (DossierAttributeEntity dossierAttributeEntity : dossierAttributeEntities) {
|
||||
attributeIdToValue.put(dossierAttributeEntity.getId().getDossierAttributeConfigId(), dossierAttributeEntity.getValue());
|
||||
}
|
||||
return new DossierAttributes(attributeIdToValue);
|
||||
}
|
||||
|
||||
private List<Dossier> enhanceDossiersWithAttributeAndACLData(List<Dossier> dossiers) {
|
||||
|
||||
return enhanceDossiersWithAttributeAndACLData(dossiers, true);
|
||||
}
|
||||
|
||||
private List<Dossier> enhanceDossiersWithAttributeAndACLData(List<Dossier> dossiers, boolean filter) {
|
||||
|
||||
// filter first, only load attributes and ACL for viewable dossiers
|
||||
List<Dossier> filteredDossiers = filter ? filterByPermissionsService.onlyViewableDossiers(dossiers) : dossiers;
|
||||
|
||||
// load all attributes at once
|
||||
var attributes = dossierAttributePersistenceService.getDossierAttributes(filteredDossiers.stream().map(Dossier::getId).collect(Collectors.toSet()));
|
||||
var attributesMap = new HashMap<String, List<DossierAttributeEntity>>();
|
||||
for (DossierAttributeEntity attribute : attributes) {
|
||||
attributesMap.computeIfAbsent(attribute.getId().getDossierId(), k -> new ArrayList<>()).add(attribute);
|
||||
}
|
||||
|
||||
for (var dossier : filteredDossiers) {
|
||||
// set attributes
|
||||
dossier.setDossierAttributes(convertDossierAttributes(attributesMap.getOrDefault(dossier.getId(), new ArrayList<>())));
|
||||
// set ACL data
|
||||
dossierACLService.enhanceDossierWithACLData(dossier);
|
||||
}
|
||||
return filteredDossiers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -14,13 +14,17 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.ColorUtils;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.DossierStatusResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierStatusRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierStatusRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierStatusInfo;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -31,6 +35,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class DossierStatusController implements DossierStatusResource {
|
||||
|
||||
private final DossierStatusPersistenceService dossierStatusPersistenceService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -57,6 +62,15 @@ public class DossierStatusController implements DossierStatusResource {
|
||||
.rank(dossierStatusRequest.getRank())
|
||||
.color(dossierStatusRequest.getColor())
|
||||
.build());
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierStatusRequest.getDossierTemplateId())
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Dossier states have been updated.")
|
||||
.build());
|
||||
|
||||
|
||||
return MagicConverter.convert(response, DossierStatusInfo.class);
|
||||
}
|
||||
|
||||
@ -91,7 +105,17 @@ public class DossierStatusController implements DossierStatusResource {
|
||||
public void deleteDossierStatus(@PathVariable("dossierStatusId") String dossierStatusId,
|
||||
@RequestParam(value = DOSSIER_STATUS_REPLACE_ID, required = false) String replaceDossierStatusId) {
|
||||
|
||||
var dossierTemplateId = dossierStatusPersistenceService.getDossierStatus(dossierStatusId).getDossierTemplateId();
|
||||
|
||||
dossierStatusPersistenceService.deleteDossierStatus(dossierStatusId, replaceDossierStatusId);
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Dossier state has been deleted.")
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStats;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.importexport.ExportDownloadRequest;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.dataexchange.models.ExportDownloadRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.importexport.ImportDossierTemplateRequest;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
@ -136,7 +136,7 @@ public class DossierTemplateController implements DossierTemplateResource {
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER_TEMPLATES + "')")
|
||||
@PreAuthorize("hasAuthority('" + WRITE_DOSSIER_TEMPLATES + "')")
|
||||
public void deleteDossierTemplates(@RequestBody List<String> dossierTemplateIds) {
|
||||
|
||||
String userId = KeycloakSecurity.getUserId();
|
||||
|
||||
@ -7,23 +7,17 @@ import java.io.BufferedInputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
@ -34,6 +28,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.AccessC
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DownloadService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils;
|
||||
@ -76,6 +71,7 @@ public class DownloadController implements DownloadResource {
|
||||
private final OneTimeTokenService oneTimeTokenDownloadService;
|
||||
private final AccessControlService accessControlService;
|
||||
private final FileManagementStorageService fileManagementStorageService;
|
||||
private final FileStatusManagementService fileStatusManagementService;
|
||||
|
||||
private final String REPORT_INFO = "/REPORT_INFO.json";
|
||||
|
||||
@ -142,7 +138,7 @@ public class DownloadController implements DownloadResource {
|
||||
if (StringUtils.isBlank(dossierId)) {
|
||||
throw new BadRequestException("Empty dossier id");
|
||||
}
|
||||
dossierService.getDossierById(dossierId, true, true);
|
||||
dossierService.getDossierById(dossierId, true, false);
|
||||
accessControlService.verifyUserIsDossierOwnerOrApprover(dossierId);
|
||||
}
|
||||
|
||||
@ -152,16 +148,19 @@ public class DownloadController implements DownloadResource {
|
||||
List<FileModel> validFiles = fileStatusService.getDossierStatus(request.getDossierId());
|
||||
var fileIds = request.getFileIds();
|
||||
if (fileIds != null && !fileIds.isEmpty()) { // validate the ids provided
|
||||
if(fileIds.size() == 1) {
|
||||
fileStatusManagementService.getFileStatus(fileIds.get(0), false);
|
||||
}
|
||||
validFiles = validFiles.stream()
|
||||
.filter(f -> fileIds.contains(f.getId()))
|
||||
.collect(Collectors.toList());
|
||||
if (validFiles.isEmpty()) {
|
||||
throw new NotFoundException("No file id provided is found");
|
||||
throw new NotFoundException("No provided file id was found");
|
||||
}
|
||||
} // otherwise consider the files from dossier
|
||||
|
||||
var validFilesAndNotProcessed = validFiles.stream()
|
||||
.filter(f -> !(f.getAnalysisVersion() > 0 && f.getNumberOfAnalyses() > 0))
|
||||
.filter(f -> !(f.getAnalysisVersion() > 0 && f.getNumberOfAnalyses() > 0 && !f.isSoftOrHardDeleted()))
|
||||
.collect(Collectors.toList());
|
||||
if (!validFilesAndNotProcessed.isEmpty()) {
|
||||
throw new BadRequestException("At least a file is in its initial analysis process");
|
||||
|
||||
@ -2,6 +2,7 @@ package com.iqser.red.persistence.service.v1.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_REDACTION_LOG;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
@ -10,10 +11,11 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.mapper.EntityLogResponseMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.EntityLogResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.FilteredEntityLogRequest;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -24,28 +26,55 @@ public class EntityLogController implements EntityLogResource {
|
||||
|
||||
private final EntityLogService entityLogService;
|
||||
private final AccessControlService accessControlService;
|
||||
private final EntityLogResponseMapper entityLogResponseMapper = EntityLogResponseMapper.INSTANCE;
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
public EntityLogResponse getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedTypes", required = false, defaultValue = "") List<String> excludedTypes,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
|
||||
accessControlService.checkViewPermissionsToDossier(dossierId);
|
||||
accessControlService.validateFileResourceExistence(fileId);
|
||||
return entityLogService.getEntityLog(dossierId, fileId, excludedTypes, includeUnprocessed);
|
||||
return entityLogResponseMapper.toLogResponse(entityLogService.getEntityLog(dossierId,
|
||||
fileId,
|
||||
excludedTypes == null ? new ArrayList<>() : excludedTypes,
|
||||
includeUnprocessed));
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public EntityLog getFilteredEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody FilteredEntityLogRequest filteredEntityLogRequest) {
|
||||
public EntityLogResponse getFilteredEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody FilteredEntityLogRequest filteredEntityLogRequest) {
|
||||
|
||||
accessControlService.checkViewPermissionsToDossier(dossierId);
|
||||
accessControlService.validateFileResourceExistence(fileId);
|
||||
return entityLogService.getFilteredEntityLog(dossierId, fileId, filteredEntityLogRequest);
|
||||
return entityLogResponseMapper.toLogResponse(entityLogService.getFilteredEntityLog(dossierId, fileId, filteredEntityLogRequest));
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public EntityLogResponse getEntityLogWithEntriesOnPages(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "pageNumbers", defaultValue = "") List<Integer> pageNumbers) {
|
||||
|
||||
accessControlService.checkViewPermissionsToDossier(dossierId);
|
||||
accessControlService.validateFileResourceExistence(fileId);
|
||||
return entityLogResponseMapper.toLogResponse(entityLogService.getEntityLogWithEntriesOnPages(dossierId, fileId, pageNumbers));
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public EntityLogResponse getEntityLogDeltaUpdate(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@PathVariable(ANALYSIS_NUMBER) Integer analysisNumber,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
|
||||
accessControlService.checkViewPermissionsToDossier(dossierId);
|
||||
accessControlService.validateFileResourceExistence(fileId);
|
||||
return entityLogResponseMapper.toLogResponse(entityLogService.getEntityLogWithEntriesWithEntriesSinceAnalysisNumber(dossierId, fileId, analysisNumber, includeUnprocessed));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -13,6 +13,9 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.model.websocket.FileEventType;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.websocket.WebsocketService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.FileAttributeConfigMapper;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.FileAttributesGeneralConfigurationEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileAttributeConfigEntity;
|
||||
@ -47,6 +50,7 @@ public class FileAttributesController implements FileAttributesResource {
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
private final FileStatusService fileStatusService;
|
||||
private final AccessControlService accessControlService;
|
||||
private final WebsocketService websocketService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -58,9 +62,9 @@ public class FileAttributesController implements FileAttributesResource {
|
||||
}
|
||||
fileAttributeConfigPersistenceService.setFileAttributesGeneralConfig(dossierTemplateId,
|
||||
MagicConverter.convert(fileAttributesConfig, FileAttributesGeneralConfigurationEntity.class));
|
||||
var result = fileAttributeConfigPersistenceService.setFileAttributesConfig(dossierTemplateId,
|
||||
MagicConverter.convert(fileAttributesConfig.getFileAttributeConfigs(),
|
||||
FileAttributeConfigEntity.class));
|
||||
fileAttributeConfigPersistenceService.setFileAttributesConfig(dossierTemplateId,
|
||||
MagicConverter.convert(fileAttributesConfig.getFileAttributeConfigs(), FileAttributeConfigEntity.class));
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
@ -71,7 +75,9 @@ public class FileAttributesController implements FileAttributesResource {
|
||||
.filenameMappingColumnHeaderName(fileAttributesConfig.getFilenameMappingColumnHeaderName())
|
||||
.delimiter(fileAttributesConfig.getDelimiter())
|
||||
.encoding(fileAttributesConfig.getEncoding())
|
||||
.fileAttributeConfigs(MagicConverter.convert(result, FileAttributeConfig.class))
|
||||
.fileAttributeConfigs(MagicConverter.convert(fileAttributeConfigPersistenceService.getFileAttributes(dossierTemplateId),
|
||||
FileAttributeConfig.class,
|
||||
new FileAttributeConfigMapper()))
|
||||
.build();
|
||||
|
||||
}
|
||||
@ -93,7 +99,7 @@ public class FileAttributesController implements FileAttributesResource {
|
||||
dossierTemplateId))
|
||||
.build());
|
||||
|
||||
return MagicConverter.convert(result, FileAttributeConfig.class);
|
||||
return MagicConverter.convert(result, FileAttributeConfig.class, new FileAttributeConfigMapper());
|
||||
}
|
||||
|
||||
|
||||
@ -142,7 +148,7 @@ public class FileAttributesController implements FileAttributesResource {
|
||||
.filenameMappingColumnHeaderName(generalConfig.getFilenameMappingColumnHeaderName())
|
||||
.delimiter(generalConfig.getDelimiter())
|
||||
.encoding(generalConfig.getEncoding())
|
||||
.fileAttributeConfigs(MagicConverter.convert(fileAttributeConfigs, FileAttributeConfig.class))
|
||||
.fileAttributeConfigs(MagicConverter.convert(fileAttributeConfigs, FileAttributeConfig.class, new FileAttributeConfigMapper()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -161,6 +167,7 @@ public class FileAttributesController implements FileAttributesResource {
|
||||
}
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
fileAttributesManagementService.setFileAttributes(dossierId, fileId, fileAttributes.getAttributeIdToValue());
|
||||
websocketService.sendFileEvent(dossierId, fileId, FileEventType.UPDATE);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
|
||||
@ -232,7 +232,7 @@ public class FileManagementController implements FileManagementResource {
|
||||
public void restoreFiles(@PathVariable(DOSSIER_ID) String dossierId, @RequestBody Set<String> fileIds) {
|
||||
|
||||
accessControlService.checkAccessPermissionsToDossier(dossierId);
|
||||
verifyUserIsDossierOwnerOrApproverOrAssignedReviewer(dossierId, fileIds);
|
||||
accessControlService.verifyUserIsDossierOwnerOrApproverOrAssignedReviewer(dossierId, fileIds);
|
||||
fileService.undeleteFiles(dossierId, fileIds);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
@ -266,11 +266,14 @@ public class FileManagementController implements FileManagementResource {
|
||||
FileModel fileModel = fileStatusManagementService.getFileStatus(fileId);
|
||||
|
||||
if (!fileModel.isExcludedFromAutomaticAnalysis()) {
|
||||
if (fileModel.getOcrStartTime() != null || fileModel.getOcrEndTime() != null) {
|
||||
reanalysisService.ocrFile(dossierId, fileId, true);
|
||||
} else {
|
||||
fileStatusService.setStatusFullReprocess(dossierId, fileId, true, true);
|
||||
}
|
||||
|
||||
// Re- ocr is files with pdftron ocr service is breaking files and not needed with azure.
|
||||
// TODO find a better solution for this.
|
||||
// if (fileModel.getOcrStartTime() != null || fileModel.getOcrEndTime() != null) {
|
||||
// reanalysisService.ocrFile(dossierId, fileId, true);
|
||||
// } else {
|
||||
fileStatusService.setStatusFullReprocess(dossierId, fileId, true, true, false);
|
||||
// }
|
||||
}
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
@ -286,20 +289,4 @@ public class FileManagementController implements FileManagementResource {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void verifyUserIsDossierOwnerOrApproverOrAssignedReviewer(String dossierId, Set<String> fileIds) {
|
||||
|
||||
try {
|
||||
accessControlService.verifyUserIsDossierOwnerOrApprover(dossierId);
|
||||
} catch (AccessDeniedException e1) {
|
||||
try {
|
||||
for (String fileId : fileIds) {
|
||||
accessControlService.verifyUserIsReviewer(dossierId, fileId);
|
||||
}
|
||||
} catch (NotAllowedException e2) {
|
||||
throw new NotAllowedException("User must be dossier owner, approver or assigned reviewer of the file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,9 +15,9 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.highlights.Highlights;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.highlights.TextHighlightConversionOperation;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.highlights.TextHighlightConversionRequest;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.highlights.TextHighlights;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
|
||||
@ -47,20 +47,20 @@ public class HighlightsController implements HighlightsResource {
|
||||
|
||||
@SneakyThrows
|
||||
@PreAuthorize("hasAuthority('" + GET_HIGHLIGHTS + "')")
|
||||
public Highlights getHighlights(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
public TextHighlights getHighlights(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndViewPermissionsToDossier(dossierId);
|
||||
fileStatusService.getStatus(fileId);
|
||||
|
||||
if (storageService.objectExists(TenantContext.getTenantId(), getStorageId(dossierId, fileId, FileType.TEXT_HIGHLIGHTS))) {
|
||||
try (InputStream stream = fileManagementStorageService.getObject(TenantContext.getTenantId(), getStorageId(dossierId, fileId, FileType.TEXT_HIGHLIGHTS))) {
|
||||
Highlights highlights = objectMapper.readValue(stream, Highlights.class);
|
||||
TextHighlights highlights = objectMapper.readValue(stream, TextHighlights.class);
|
||||
stream.close();
|
||||
return highlights;
|
||||
}
|
||||
}
|
||||
|
||||
return new Highlights();
|
||||
return new TextHighlights();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_SIMILAR_IMAGES;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.commons.spring.ErrorMessage;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ImageSimilarityService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.ImageSimilaritySearchResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.image.ImageSimilaritySearchRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.image.ImageSimilaritySearchResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ImageDocument;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ImageSimilaritySearchController implements ImageSimilaritySearchResource {
|
||||
|
||||
private final ImageSimilarityService imageSimilarityService;
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@PreAuthorize("hasAuthority('" + GET_SIMILAR_IMAGES + "')")
|
||||
public ResponseEntity getSimilarImages(@RequestBody ImageSimilaritySearchRequest imageSimilaritySearchRequest) {
|
||||
|
||||
log.info("received similiar image search request {}", imageSimilaritySearchRequest);
|
||||
if (imageSimilaritySearchRequest.getAnnotationId().isEmpty() || (imageSimilaritySearchRequest.getScope().getFileId().isEmpty() && imageSimilaritySearchRequest.getScope()
|
||||
.getTemplateId()
|
||||
.isEmpty() && imageSimilaritySearchRequest.getScope().getDossierId().isEmpty())) {
|
||||
return new ResponseEntity<>(new ErrorMessage(OffsetDateTime.now(), "Required parameter missing"), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
List<ImageDocument> similarImages = this.imageSimilarityService.findSimilarImages(imageSimilaritySearchRequest.getAnnotationId(),
|
||||
imageSimilaritySearchRequest.getDistance(),
|
||||
imageSimilaritySearchRequest.getScope());
|
||||
List<String> similarImagesIds = new ArrayList<>();
|
||||
List<Byte> similarImagesThumbnails = new ArrayList<>();
|
||||
similarImages.stream()
|
||||
.forEach(doc -> {
|
||||
similarImagesIds.add(doc.getImageId());
|
||||
similarImagesThumbnails.add(doc.getThumbnail());
|
||||
});
|
||||
ImageSimilaritySearchResponse imageSimilaritySearchResponse = new ImageSimilaritySearchResponse(similarImagesIds, similarImagesThumbnails);
|
||||
return new ResponseEntity<>(imageSimilaritySearchResponse, HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,22 +5,21 @@ import static com.iqser.red.service.persistence.management.v1.processor.roles.Ac
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.LegalBasisMappingResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.legalbasis.LegalBasis;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@ -33,9 +32,9 @@ public class LegalBasisMappingController implements LegalBasisMappingResource {
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_LEGAL_BASIS + "')")
|
||||
public void deleteLegalBasis(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestBody List<String> legalBasisNames) {
|
||||
public void deleteLegalBasis(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestBody List<String> legalBasisTechnicalNames) {
|
||||
|
||||
legalBasisMappingPersistenceService.deleteLegalBasis(dossierTemplateId, legalBasisNames);
|
||||
legalBasisMappingPersistenceService.deleteLegalBasis(dossierTemplateId, legalBasisTechnicalNames);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
|
||||
@ -6,9 +6,13 @@ import static com.iqser.red.service.persistence.management.v1.processor.roles.Ac
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.DO_MANUAL_REDACTION;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_MANUAL_REDACTIONS;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@ -16,37 +20,48 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.mapper.EntityLogResponseMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.CommentService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionUndoService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.PendingEntryFactory;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntryResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationComments;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.LegalBasisChangeRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAnnotationResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactionResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RemoveRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ResizeRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionBulkLocalRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationBulkLocalRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionBulkLocalRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.EntityLogMongoService;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
@ -63,32 +78,38 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
static final String FILE_ID = "fileId";
|
||||
static final String DOSSIER_ID = "dossierId";
|
||||
static final String ANNOTATION_ID = "annotationId";
|
||||
|
||||
ManualRedactionService manualRedactionService;
|
||||
ManualRedactionUndoService manualRedactionUndoService;
|
||||
DossierManagementService dossierManagementService;
|
||||
AuditPersistenceService auditPersistenceService;
|
||||
AccessControlService accessControlService;
|
||||
ManualRedactionMapper manualRedactionMapper;
|
||||
CommentService commentService;
|
||||
FileStatusManagementService fileStatusManagementService;
|
||||
FileStatusService fileStatusService;
|
||||
EntityLogMongoService entityLogMongoService;
|
||||
PendingEntryFactory pendingEntryFactory;
|
||||
DictionaryPersistenceService dictionaryPersistenceService;
|
||||
|
||||
EntityLogController entityLogController;
|
||||
EntityLogResponseMapper mapper = EntityLogResponseMapper.INSTANCE;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + DELETE_MANUAL_REDACTION + "')")
|
||||
public void undo(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<String> annotationIds,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
@RequestParam(value = "includeOnlyUnprocessed", required = false, defaultValue = FALSE) boolean includeOnlyUnprocessed,
|
||||
@RequestParam(value = "includeOnlyLocal", required = false, defaultValue = FALSE) boolean includeOnlyLocal) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
manualRedactionUndoService.undo(dossierId, fileId, annotationIds, includeUnprocessed);
|
||||
manualRedactionUndoService.undo(dossierId, fileId, annotationIds, includeOnlyUnprocessed, includeOnlyLocal);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + DELETE_COMMENT + "')")
|
||||
public void undoComment(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@ -111,7 +132,6 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')")
|
||||
public ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@ -120,12 +140,12 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
|
||||
accessControlService.checkDossierExistenceAndViewPermissionsToDossier(dossierId);
|
||||
accessControlService.validateFileResourceExistence(fileId);
|
||||
|
||||
return manualRedactionService.getManualRedactions(fileId,
|
||||
ManualChangesQueryOptions.builder().includeOnlyUnprocessed(unprocessed).includeDictChanges(includeDictChanges).build());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')")
|
||||
public AnnotationComments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @PathVariable(ANNOTATION_ID) String annotationId) {
|
||||
|
||||
@ -138,7 +158,6 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + ADD_COMMENT + "')")
|
||||
public CommentResponse addComment(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@ -163,108 +182,172 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
public ManualRedactionResponse addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<AddRedactionRequestModel> addRedactionRequests) {
|
||||
|
||||
var dossier = dossierManagementService.getDossierById(dossierId, false, false);
|
||||
accessControlService.checkAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
if (addRedactionRequests.stream()
|
||||
.anyMatch(AddRedactionRequestModel::isAddToAllDossiers)) {
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
} else {
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
}
|
||||
verifyAccessForDossier(dossierId,
|
||||
fileId,
|
||||
addRedactionRequests.stream()
|
||||
.anyMatch(AddRedactionRequestModel::isAddToAllDossiers));
|
||||
|
||||
List<AddRedactionRequest> requests = manualRedactionMapper.toAddRedactionRequestList(dossierId, addRedactionRequests, dossier);
|
||||
|
||||
List<ManualAddResponse> responseList = manualRedactionService.addAddRedaction(dossierId, fileId, requests);
|
||||
List<ManualAnnotationResponse> responseList = manualRedactionService.addAddRedaction(dossierId, fileId, addRedactionRequests, dossier);
|
||||
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Manual redaction was added.")
|
||||
.message("Manual annotation was added.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
|
||||
.build()));
|
||||
|
||||
return responseList;
|
||||
return ManualRedactionResponse.builder().manualAnnotationResponses(responseList).build();
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
public ManualRedactionResponse addRedactionBulkLocal(String dossierId, String fileId, AddRedactionBulkLocalRequestModel addRedactionRequest) {
|
||||
|
||||
verifyAccess(dossierId, fileId);
|
||||
|
||||
// check if type exists before sending the request to redaction service
|
||||
var dossier = dossierManagementService.getDossierById(dossierId, false, false);
|
||||
dictionaryPersistenceService.getType(TypeIdUtils.toTypeId(addRedactionRequest.getType(), dossier.getDossierTemplateId()));
|
||||
|
||||
if (!addRedactionRequest.isRectangle()) {
|
||||
fileStatusService.setStatusBulkLocalRedactionsProcessing(fileId, addRedactionRequest);
|
||||
|
||||
EntityLogEntry entityLogEntry = pendingEntryFactory.buildAddRedactionBulkLocalEntry(addRedactionRequest);
|
||||
|
||||
return ManualRedactionResponse.builder()
|
||||
.manualAnnotationResponses(List.of(ManualAnnotationResponse.builder()
|
||||
.annotationId(manualRedactionService.getNewAnnotationId())
|
||||
.entityLogEntry(entityLogEntry)
|
||||
.build()))
|
||||
.build();
|
||||
} else {
|
||||
Set<AddRedactionRequestModel> addRedactionRequestModels = addRedactionRequest.getPageNumbers()
|
||||
.stream()
|
||||
.map(page -> AddRedactionRequestModel.builder()
|
||||
.type(addRedactionRequest.getType())
|
||||
.value(addRedactionRequest.getValue())
|
||||
.reason(addRedactionRequest.getReason())
|
||||
.legalBasis(addRedactionRequest.getLegalBasis())
|
||||
.positions(addRedactionRequest.getPositions()
|
||||
.stream()
|
||||
.map(rectangle -> Rectangle.createRectangle(rectangle.getTopLeftX(),
|
||||
rectangle.getTopLeftY(),
|
||||
rectangle.getWidth(),
|
||||
rectangle.getHeight(),
|
||||
page))
|
||||
.toList())
|
||||
.comment(addRedactionRequest.getComment() != null ? AddCommentRequestModel.builder().text(addRedactionRequest.getComment()).build() : null)
|
||||
.section(addRedactionRequest.getSection())
|
||||
.rectangle(true)
|
||||
.build())
|
||||
.collect(Collectors.toSet());
|
||||
return addRedactionBulk(dossierId, fileId, addRedactionRequestModels);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public ManualRedactionResponse removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<RemoveRedactionRequestModel> removeRedactionRequests,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
@RequestBody Set<RemoveRedactionRequestModel> removeRedactionRequests) {
|
||||
|
||||
var dossier = dossierManagementService.getDossierById(dossierId, false, false);
|
||||
accessControlService.checkAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
if (removeRedactionRequests.stream()
|
||||
.anyMatch(RemoveRedactionRequestModel::isRemoveFromAllDossiers)) {
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
} else {
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
}
|
||||
verifyAccessForDossier(dossierId,
|
||||
fileId,
|
||||
removeRedactionRequests.stream()
|
||||
.anyMatch(RemoveRedactionRequestModel::isRemoveFromAllDossiers));
|
||||
|
||||
List<RemoveRedactionRequest> requests = manualRedactionMapper.toRemoveRedactionRequestList(dossierId,
|
||||
fileId,
|
||||
dossier.getDossierTemplateId(),
|
||||
removeRedactionRequests,
|
||||
includeUnprocessed);
|
||||
List<ManualAddResponse> responseList = manualRedactionService.addRemoveRedaction(dossierId, fileId, requests);
|
||||
List<ManualAnnotationResponse> responseList = manualRedactionService.addRemoveRedaction(dossierId, fileId, removeRedactionRequests, dossier.getDossierTemplateId(), true);
|
||||
|
||||
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Redaction was manually removed")
|
||||
.message("Annotation was manually removed")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
|
||||
.build()));
|
||||
|
||||
return responseList;
|
||||
return ManualRedactionResponse.builder().manualAnnotationResponses(responseList).build();
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
public ManualRedactionResponse removeRedactionBulkLocal(String dossierId, String fileId, RemoveRedactionBulkLocalRequestModel removeRedactionRequest) {
|
||||
|
||||
verifyAccess(dossierId, fileId);
|
||||
verifyRequest(removeRedactionRequest.isRectangle(), removeRedactionRequest.getPosition(), removeRedactionRequest.getValue());
|
||||
|
||||
Set<RemoveRedactionRequestModel> removeRedactionRequestModels;
|
||||
FileModel status = fileStatusService.getStatus(fileId);
|
||||
|
||||
Set<EntityLogEntry> entries;
|
||||
if (!status.isExcludedFromAutomaticAnalysis()) {
|
||||
entries = getFilteredEntityLogEntries(dossierId,
|
||||
fileId,
|
||||
removeRedactionRequest.isRectangle(),
|
||||
removeRedactionRequest.getValue(),
|
||||
removeRedactionRequest.isCaseSensitive(),
|
||||
removeRedactionRequest.getOriginTypes(),
|
||||
removeRedactionRequest.getOriginLegalBases(),
|
||||
removeRedactionRequest.getPageNumbers(),
|
||||
removeRedactionRequest.getPosition());
|
||||
|
||||
} else {
|
||||
|
||||
entries = new HashSet<>(mapper.fromLogEntryResponses(getFilteredEntityLogResponses(dossierId,
|
||||
fileId,
|
||||
removeRedactionRequest.isRectangle(),
|
||||
removeRedactionRequest.getValue(),
|
||||
removeRedactionRequest.isCaseSensitive(),
|
||||
removeRedactionRequest.getOriginTypes(),
|
||||
removeRedactionRequest.getOriginLegalBases(),
|
||||
removeRedactionRequest.getPageNumbers(),
|
||||
removeRedactionRequest.getPosition())));
|
||||
}
|
||||
|
||||
removeRedactionRequestModels = entries.stream()
|
||||
.map(entityLogEntry -> RemoveRedactionRequestModel.builder().annotationId(entityLogEntry.getId()).comment(removeRedactionRequest.getComment()).build())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return removeRedactionBulk(dossierId, fileId, removeRedactionRequestModels);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public ManualRedactionResponse forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ForceRedactionRequestModel> forceRedactionRequests) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
verifyAccessAndDossierExistence(dossierId, fileId);
|
||||
|
||||
List<ForceRedactionRequest> requests = manualRedactionMapper.toForceRedactionRequestList(forceRedactionRequests);
|
||||
List<ManualAddResponse> responseList = manualRedactionService.addForceRedaction(dossierId, fileId, requests);
|
||||
List<ManualAnnotationResponse> responseList = manualRedactionService.addForceRedaction(dossierId, fileId, forceRedactionRequests);
|
||||
|
||||
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Skipped redaction was forced to be redacted")
|
||||
.message("Skipped annotation was forced to be applied")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
|
||||
.build()));
|
||||
|
||||
return responseList;
|
||||
return ManualRedactionResponse.builder().manualAnnotationResponses(responseList).build();
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
public ManualRedactionResponse legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<LegalBasisChangeRequestModel> legalBasisChangeRequests) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
verifyAccessAndDossierExistence(dossierId, fileId);
|
||||
|
||||
List<LegalBasisChangeRequest> requests = manualRedactionMapper.toLegalBasisChangeRequestList(legalBasisChangeRequests);
|
||||
|
||||
List<ManualAddResponse> responseList = manualRedactionService.addLegalBasisChange(dossierId, fileId, requests);
|
||||
List<ManualAnnotationResponse> responseList = manualRedactionService.addLegalBasisChange(dossierId, fileId, legalBasisChangeRequests);
|
||||
|
||||
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
@ -274,28 +357,19 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
|
||||
.build()));
|
||||
|
||||
return responseList;
|
||||
return ManualRedactionResponse.builder().manualAnnotationResponses(responseList).build();
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> recategorizeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
public ManualRedactionResponse recategorizeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<RecategorizationRequestModel> recategorizationRequests,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
@RequestBody Set<RecategorizationRequestModel> recategorizationRequests) {
|
||||
|
||||
var dossier = dossierManagementService.getDossierById(dossierId, false, false);
|
||||
accessControlService.checkAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
verifyAccess(dossierId, fileId);
|
||||
|
||||
List<RecategorizationRequest> requests = manualRedactionMapper.toRecategorizationRequestList(dossierId,
|
||||
fileId,
|
||||
dossier.getDossierTemplateId(),
|
||||
recategorizationRequests,
|
||||
includeUnprocessed);
|
||||
|
||||
List<ManualAddResponse> responseList = manualRedactionService.addRecategorization(dossierId, fileId, requests);
|
||||
List<ManualAnnotationResponse> responseList = manualRedactionService.addRecategorization(dossierId, fileId, dossier, recategorizationRequests, true);
|
||||
|
||||
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
@ -305,32 +379,239 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
|
||||
.build()));
|
||||
|
||||
return responseList;
|
||||
return ManualRedactionResponse.builder().manualAnnotationResponses(responseList).build();
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
public ManualRedactionResponse recategorizeBulkLocal(String dossierId, String fileId, RecategorizationBulkLocalRequestModel recategorizationRequest) {
|
||||
|
||||
verifyAccess(dossierId, fileId);
|
||||
verifyRequest(recategorizationRequest.isRectangle(), recategorizationRequest.getPosition(), recategorizationRequest.getValue());
|
||||
Set<RecategorizationRequestModel> recategorizationRequestModels;
|
||||
FileModel status = fileStatusService.getStatus(fileId);
|
||||
|
||||
Set<EntityLogEntry> entries;
|
||||
if (!status.isExcludedFromAutomaticAnalysis()) {
|
||||
entries = getFilteredEntityLogEntries(dossierId,
|
||||
fileId,
|
||||
recategorizationRequest.isRectangle(),
|
||||
recategorizationRequest.getValue(),
|
||||
recategorizationRequest.isCaseSensitive(),
|
||||
recategorizationRequest.getOriginTypes(),
|
||||
recategorizationRequest.getOriginLegalBases(),
|
||||
recategorizationRequest.getPageNumbers(),
|
||||
recategorizationRequest.getPosition());
|
||||
|
||||
} else {
|
||||
|
||||
entries = new HashSet<>(mapper.fromLogEntryResponses(getFilteredEntityLogResponses(dossierId,
|
||||
fileId,
|
||||
recategorizationRequest.isRectangle(),
|
||||
recategorizationRequest.getValue(),
|
||||
recategorizationRequest.isCaseSensitive(),
|
||||
recategorizationRequest.getOriginTypes(),
|
||||
recategorizationRequest.getOriginLegalBases(),
|
||||
recategorizationRequest.getPageNumbers(),
|
||||
recategorizationRequest.getPosition())));
|
||||
}
|
||||
|
||||
recategorizationRequestModels = entries.stream()
|
||||
.map(entry -> RecategorizationRequestModel.builder()
|
||||
.annotationId(entry.getId())
|
||||
.type(recategorizationRequest.isRectangle() ? entry.getType() : recategorizationRequest.getType())
|
||||
.legalBasis(recategorizationRequest.getLegalBasis())
|
||||
.section(recategorizationRequest.getSection())
|
||||
.value(recategorizationRequest.isRectangle() ? recategorizationRequest.getValue() : entry.getValue())
|
||||
.comment(recategorizationRequest.getComment())
|
||||
.build())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return recategorizeBulk(dossierId, fileId, recategorizationRequestModels);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public ManualRedactionResponse resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ResizeRedactionRequestModel> resizeRedactionRequests,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
@RequestBody Set<ResizeRedactionRequestModel> resizeRedactionRequests) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
verifyAccessAndDossierExistence(dossierId, fileId);
|
||||
|
||||
List<ResizeRedactionRequest> requests = manualRedactionMapper.toResizeRedactionRequestList(resizeRedactionRequests);
|
||||
List<ManualAddResponse> responseList = manualRedactionService.addResizeRedaction(dossierId, fileId, requests, includeUnprocessed);
|
||||
List<ManualAnnotationResponse> responseList = manualRedactionService.addResizeRedaction(dossierId, fileId, resizeRedactionRequests, true);
|
||||
|
||||
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Skipped redaction was resized to be redacted")
|
||||
.message("Skipped annotation was resized to be redacted")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
|
||||
.build()));
|
||||
|
||||
return responseList;
|
||||
return ManualRedactionResponse.builder().manualAnnotationResponses(responseList).build();
|
||||
}
|
||||
|
||||
|
||||
private Set<EntityLogEntry> getFilteredEntityLogEntries(String dossierId,
|
||||
String fileId,
|
||||
boolean rectangle,
|
||||
String value,
|
||||
boolean caseSensitive,
|
||||
Set<String> originTypes,
|
||||
Set<String> originLegalBases,
|
||||
Set<Integer> pageNumbers,
|
||||
Position position) {
|
||||
|
||||
Set<EntityLogEntry> entries;
|
||||
if (!rectangle) {
|
||||
entries = entityLogMongoService.findEntriesByValueWithFilters(dossierId, fileId, value, caseSensitive, originTypes, originLegalBases, pageNumbers);
|
||||
} else {
|
||||
entries = entityLogMongoService.findEntriesByMatchingFullPositionWithFilters(dossierId, fileId, position.getRectangle(), originTypes, originLegalBases, pageNumbers);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
|
||||
private List<EntityLogEntryResponse> getFilteredEntityLogResponses(String dossierId,
|
||||
String fileId,
|
||||
boolean rectangle,
|
||||
String value,
|
||||
boolean caseSensitive,
|
||||
Set<String> originTypes,
|
||||
Set<String> originLegalBases,
|
||||
Set<Integer> pageNumbers,
|
||||
Position position) {
|
||||
|
||||
List<EntityLogEntryResponse> entityLogEntryResponses = entityLogController.getEntityLog(dossierId, fileId, Collections.emptyList(), true).getEntityLogEntry()
|
||||
.stream()
|
||||
.filter(entityLogEntryResponse -> !entityLogEntryResponse.getState().equals(EntryState.PENDING))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!rectangle) {
|
||||
entityLogEntryResponses = filterEntriesByValueWithFilters(entityLogEntryResponses, value, caseSensitive, originTypes, originLegalBases, pageNumbers);
|
||||
} else {
|
||||
entityLogEntryResponses = filterEntriesByMatchingPositionWithFilters(entityLogEntryResponses, position.getRectangle(), originTypes, originLegalBases, pageNumbers);
|
||||
}
|
||||
|
||||
return entityLogEntryResponses;
|
||||
}
|
||||
|
||||
|
||||
public List<EntityLogEntryResponse> filterEntriesByValueWithFilters(List<EntityLogEntryResponse> entries,
|
||||
String value,
|
||||
boolean caseSensitive,
|
||||
Set<String> originTypes,
|
||||
Set<String> originLegalBases,
|
||||
Set<Integer> pageNumbers) {
|
||||
|
||||
return entries.stream()
|
||||
.filter(entry -> !entry.getEntryType().equals(EntryType.AREA))
|
||||
.filter(entry -> filterByValue(entry, value, caseSensitive))
|
||||
.filter(entry -> filterByOriginType(entry, originTypes))
|
||||
.filter(entry -> filterByLegalBases(entry, originLegalBases))
|
||||
.filter(entry -> filterByPageNumbers(entry, pageNumbers))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
public List<EntityLogEntryResponse> filterEntriesByMatchingPositionWithFilters(List<EntityLogEntryResponse> entries,
|
||||
float[] rectangle,
|
||||
Set<String> originTypes,
|
||||
Set<String> originLegalBases,
|
||||
Set<Integer> pageNumbers) {
|
||||
|
||||
return entries.stream()
|
||||
.filter(entry -> entry.getEntryType().equals(EntryType.AREA))
|
||||
.filter(entry -> filterByRectangle(entry, rectangle))
|
||||
.filter(entry -> filterByOriginType(entry, originTypes))
|
||||
.filter(entry -> filterByLegalBases(entry, originLegalBases))
|
||||
.filter(entry -> filterByPageNumbers(entry, pageNumbers))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
private boolean filterByValue(EntityLogEntryResponse entry, String value, boolean caseSensitive) {
|
||||
|
||||
if (caseSensitive) {
|
||||
return entry.getValue().equals(value);
|
||||
} else {
|
||||
return entry.getValue().equalsIgnoreCase(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean filterByOriginType(EntityLogEntryResponse entry, Set<String> originTypes) {
|
||||
|
||||
return originTypes == null || originTypes.isEmpty() || originTypes.contains(entry.getType());
|
||||
}
|
||||
|
||||
|
||||
private boolean filterByLegalBases(EntityLogEntryResponse entry, Set<String> originLegalBases) {
|
||||
|
||||
return originLegalBases == null || originLegalBases.isEmpty() || originLegalBases.contains(entry.getLegalBasis());
|
||||
}
|
||||
|
||||
|
||||
private boolean filterByPageNumbers(EntityLogEntryResponse entry, Set<Integer> pageNumbers) {
|
||||
|
||||
if (pageNumbers == null || pageNumbers.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return entry.getPositions()
|
||||
.stream()
|
||||
.anyMatch(pos -> pageNumbers.contains(pos.getPageNumber()));
|
||||
}
|
||||
|
||||
|
||||
private boolean filterByRectangle(EntityLogEntryResponse entry, float[] rectangle) {
|
||||
|
||||
if (rectangle == null || rectangle.length == 0) {
|
||||
return true;
|
||||
}
|
||||
return entry.getPositions()
|
||||
.stream()
|
||||
.anyMatch(pos -> Arrays.equals(pos.getRectangle(), rectangle));
|
||||
}
|
||||
|
||||
|
||||
private void verifyRequest(boolean isRectangle, Position position, String value) {
|
||||
|
||||
if (isRectangle && position == null) {
|
||||
throw new BadRequestException("Position must be set for rectangle annotations.");
|
||||
}
|
||||
|
||||
if (!isRectangle && value == null) {
|
||||
throw new BadRequestException("Value must be set.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void verifyAccessForDossier(String dossierId, String fileId, boolean allDossiersAffected) {
|
||||
|
||||
accessControlService.checkAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
if (allDossiersAffected) {
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
} else {
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void verifyAccess(String dossierId, String fileId) {
|
||||
|
||||
accessControlService.checkAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
}
|
||||
|
||||
|
||||
private void verifyAccessAndDossierExistence(String dossierId, String fileId) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.migration.SaasMigrationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.SaasMigrationStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.MigrationStatusResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.saas.migration.MigrationStatusResponse;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus.*;
|
||||
|
||||
@RestController
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
@RequiredArgsConstructor
|
||||
public class MigrationStatusController implements MigrationStatusResource {
|
||||
|
||||
SaasMigrationService saasMigrationService;
|
||||
|
||||
SaasMigrationStatusPersistenceService saasMigrationStatusPersistenceService;
|
||||
|
||||
FileStatusService fileStatusService;
|
||||
|
||||
|
||||
public MigrationStatusResponse migrationStatus() {
|
||||
|
||||
int numberOfFilesToMigrate = saasMigrationStatusPersistenceService.countAll();
|
||||
|
||||
Map<SaasMigrationStatus, Integer> filesInStatus = new HashMap<>();
|
||||
filesInStatus.put(MIGRATION_REQUIRED, saasMigrationStatusPersistenceService.countByStatus(MIGRATION_REQUIRED));
|
||||
filesInStatus.put(DOCUMENT_FILES_MIGRATED, saasMigrationStatusPersistenceService.countByStatus(DOCUMENT_FILES_MIGRATED));
|
||||
filesInStatus.put(REDACTION_LOGS_MIGRATED, saasMigrationStatusPersistenceService.countByStatus(REDACTION_LOGS_MIGRATED));
|
||||
filesInStatus.put(ANNOTATION_IDS_MIGRATED, saasMigrationStatusPersistenceService.countByStatus(ANNOTATION_IDS_MIGRATED));
|
||||
filesInStatus.put(FINISHED, saasMigrationStatusPersistenceService.countByStatus(FINISHED));
|
||||
filesInStatus.put(ERROR, saasMigrationStatusPersistenceService.countByStatus(ERROR));
|
||||
|
||||
var filesInErrorState = saasMigrationStatusPersistenceService.findAllByStatus(ERROR);
|
||||
|
||||
Map<String, String> errorCauses = new HashMap<>();
|
||||
filesInErrorState.forEach(errorFile -> {
|
||||
errorCauses.put(errorFile.getFileId(), errorFile.getErrorCause());
|
||||
});
|
||||
|
||||
return MigrationStatusResponse.builder().numberOfFilesToMigrate(numberOfFilesToMigrate).filesInStatus(filesInStatus).errorCauses(errorCauses).build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ResponseEntity<?> startMigrationForFile(String dossierId, String fileId) {
|
||||
|
||||
if (!fileStatusService.fileExists(fileId)) {
|
||||
throw new NotFoundException(String.format("File with id %s does not exist", fileId));
|
||||
}
|
||||
|
||||
saasMigrationService.startMigrationForFile(dossierId, fileId);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ResponseEntity<?> revertMigrationForFile(String dossierId, String fileId) {
|
||||
|
||||
if (!fileStatusService.fileExists(fileId)) {
|
||||
throw new NotFoundException(String.format("File with id %s does not exist", fileId));
|
||||
}
|
||||
|
||||
if (!saasMigrationStatusPersistenceService.findById(fileId).getStatus().equals(FINISHED)) {
|
||||
throw new BadRequestException(String.format("File with id %s is not migrated yet, can't revert.", fileId));
|
||||
}
|
||||
|
||||
saasMigrationService.revertMigrationForFile(dossierId, fileId);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ResponseEntity<?> requeueErrorFiles() {
|
||||
|
||||
MigrationStatusResponse migrationStatus = migrationStatus();
|
||||
if (!migrationIsFinished(migrationStatus)) {
|
||||
throw new BadRequestException("There are still files processing, please wait until migration has finished to retry!");
|
||||
}
|
||||
|
||||
saasMigrationService.requeueErrorFiles();
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
|
||||
private static boolean migrationIsFinished(MigrationStatusResponse migrationStatus) {
|
||||
|
||||
return migrationStatus.getFilesInStatus().entrySet()
|
||||
.stream()
|
||||
.filter(e -> e.getValue() > 0)
|
||||
.allMatch(e -> e.getKey().equals(FINISHED) || e.getKey().equals(ERROR));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,287 +0,0 @@
|
||||
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_RSS;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentLogService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentOverrideService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.RSSResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntityReference;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentsOverrides;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSFileResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSResponse;
|
||||
import com.iqser.red.service.redaction.report.v1.api.model.rss.DetailedRSSFileResponse;
|
||||
import com.iqser.red.service.redaction.report.v1.api.model.rss.DetailedRSSResponse;
|
||||
import com.iqser.red.service.redaction.report.v1.api.model.rss.SCMComponent;
|
||||
import com.iqser.red.service.redaction.report.v1.api.model.rss.ScmAnnotation;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnProperty(name = "application.rss.component-log.enabled", havingValue = "true")
|
||||
public class RSSComponentLogController implements RSSResource {
|
||||
|
||||
private final ComponentOverrideService componentOverrideService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
private final ComponentLogService componentLogService;
|
||||
private final StatusController statusController;
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public RSSResponse getRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId) {
|
||||
|
||||
List<FileStatus> dossierFiles;
|
||||
if (StringUtils.isBlank(fileId)) {
|
||||
dossierFiles = statusController.getDossierStatus(dossierId);
|
||||
} else {
|
||||
dossierFiles = List.of(statusController.getFileStatus(dossierId, fileId));
|
||||
}
|
||||
|
||||
List<RSSFileResponse> fileResponses = dossierFiles.stream()
|
||||
.map(this::getRssResponse)
|
||||
.toList();
|
||||
|
||||
return new RSSResponse(fileResponses);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private RSSFileResponse getRssResponse(FileStatus file) {
|
||||
|
||||
var componentLog = componentLogService.getComponentLog(file.getDossierId(), file.getId(), true);
|
||||
|
||||
Map<String, String> results = new LinkedHashMap<>();
|
||||
|
||||
componentLog.getComponentLogEntries()
|
||||
.forEach(entry -> {
|
||||
if (entry.getComponentValues().size() <= 1) {
|
||||
results.put(entry.getName(),
|
||||
entry.getComponentValues()
|
||||
.get(0).getValue());
|
||||
return;
|
||||
}
|
||||
|
||||
List<ComponentLogEntryValue> componentValues = entry.getComponentValues();
|
||||
for (int i = 0, componentValuesSize = componentValues.size(); i < componentValuesSize; i++) {
|
||||
ComponentLogEntryValue v = componentValues.get(i);
|
||||
results.put(entry.getName() + "_" + (i + 1), v.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
return RSSFileResponse.builder().filename(file.getFilename()).result(results).build();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public DetailedRSSResponse getDetailedRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId) {
|
||||
|
||||
List<FileStatus> dossierFiles;
|
||||
if (StringUtils.isBlank(fileId)) {
|
||||
dossierFiles = statusController.getDossierStatus(dossierId);
|
||||
} else {
|
||||
dossierFiles = List.of(statusController.getFileStatus(dossierId, fileId));
|
||||
}
|
||||
|
||||
List<DetailedRSSFileResponse> fileResponses = dossierFiles.stream()
|
||||
.map(this::getDetailedRssResponse)
|
||||
.toList();
|
||||
|
||||
return new DetailedRSSResponse(fileResponses);
|
||||
}
|
||||
|
||||
|
||||
private DetailedRSSFileResponse getDetailedRssResponse(FileStatus file) {
|
||||
|
||||
var componentLog = componentLogService.getComponentLog(file.getDossierId(), file.getId(), true);
|
||||
|
||||
Map<String, SCMComponent> results = new LinkedHashMap<>();
|
||||
|
||||
componentLog.getComponentLogEntries()
|
||||
.forEach(entry -> {
|
||||
if (entry.getComponentValues().size() <= 1) {
|
||||
results.put(entry.getName(),
|
||||
toSCMComponent(entry.getComponentValues()
|
||||
.get(0)));
|
||||
return;
|
||||
}
|
||||
|
||||
List<ComponentLogEntryValue> componentValues = entry.getComponentValues();
|
||||
for (int i = 0, componentValuesSize = componentValues.size(); i < componentValuesSize; i++) {
|
||||
ComponentLogEntryValue v = componentValues.get(i);
|
||||
results.put(entry.getName() + "_" + (i + 1), toSCMComponent(v));
|
||||
}
|
||||
});
|
||||
|
||||
return DetailedRSSFileResponse.builder().filename(file.getFilename()).result(results).build();
|
||||
}
|
||||
|
||||
|
||||
private SCMComponent toSCMComponent(ComponentLogEntryValue v) {
|
||||
|
||||
return SCMComponent.builder()
|
||||
.value(v.getValue().equals(v.getOriginalValue()) ? null : v.getValue())
|
||||
.originalValue(v.getOriginalValue())
|
||||
.transformation(v.getValueDescription())
|
||||
.scmAnnotations(v.getComponentLogEntityReferences()
|
||||
.stream()
|
||||
.map(this::toScmAnnotation)
|
||||
.toList())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private ScmAnnotation toScmAnnotation(ComponentLogEntityReference er) {
|
||||
|
||||
return ScmAnnotation.builder().type(er.getType()).pages(Set.of(er.getPage())).ruleIdentifier(er.getEntityRuleId()).reason(formatType(er.getType())).build();
|
||||
}
|
||||
|
||||
|
||||
private static String formatType(String type) {
|
||||
|
||||
return type.substring(0, 1).toUpperCase(Locale.ENGLISH) + type.substring(1).toLowerCase(Locale.ENGLISH).replaceAll("_", " ");
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides) {
|
||||
|
||||
var componentLog = componentLogService.getComponentLog(dossierId, fileId);
|
||||
var allComponents = componentLog.getComponentLogEntries();
|
||||
|
||||
componentOverrideService.addOverrides(dossierId, fileId, componentsOverrides);
|
||||
|
||||
componentsOverrides.getComponentOverrides()
|
||||
.forEach((componentName, overrideValue) -> auditOverride(dossierId, fileId, componentName, overrideValue, allComponents));
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
return componentOverrideService.getOverrides(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest) {
|
||||
|
||||
var componentLog = componentLogService.getComponentLog(dossierId, fileId);
|
||||
var allComponents = componentLog.getComponentLogEntries();
|
||||
|
||||
componentOverrideService.revertOverrides(dossierId, fileId, revertOverrideRequest);
|
||||
|
||||
revertOverrideRequest.getComponents()
|
||||
.forEach(componentNameToRevert -> auditOverrideRevert(dossierId, fileId, componentNameToRevert, allComponents));
|
||||
}
|
||||
|
||||
|
||||
private void auditOverride(String dossierId, String fileId, String componentName, String overrideValue, List<ComponentLogEntry> allComponentLogEntries) {
|
||||
|
||||
Optional<ComponentLogEntry> component = allComponentLogEntries.stream()
|
||||
.filter(c -> c.getName().equals(componentName))
|
||||
.findFirst();
|
||||
String originalValue = getOriginalValue(component);
|
||||
String value = getValue(component);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("The component is overwritten with value")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
"ComponentName",
|
||||
componentName,
|
||||
"Action",
|
||||
"MODIFY",
|
||||
"OriginalValue",
|
||||
originalValue,
|
||||
"OldValue",
|
||||
value,
|
||||
"NewValue",
|
||||
overrideValue))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private void auditOverrideRevert(String dossierId, String fileId, String componentNameToRevert, List<ComponentLogEntry> allComponentLogEntries) {
|
||||
|
||||
Optional<ComponentLogEntry> component = allComponentLogEntries.stream()
|
||||
.filter(c -> c.getName().equals(componentNameToRevert))
|
||||
.findFirst();
|
||||
String originalValue = getOriginalValue(component);
|
||||
String value = getValue(component);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("The component override for was reverted")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
"ComponentName",
|
||||
componentNameToRevert,
|
||||
"Action",
|
||||
"REVERT",
|
||||
"OriginalValue",
|
||||
originalValue,
|
||||
"OldValue",
|
||||
value,
|
||||
"NewValue",
|
||||
originalValue))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private String getValue(Optional<ComponentLogEntry> component) {
|
||||
|
||||
return component.map(ComponentLogEntry::getComponentValues)
|
||||
.stream()
|
||||
.map(a -> a.stream()
|
||||
.map(ComponentLogEntryValue::getValue)
|
||||
.collect(Collectors.joining(", ")))
|
||||
.findFirst()
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
|
||||
private static String getOriginalValue(Optional<ComponentLogEntry> component) {
|
||||
|
||||
return component.map(ComponentLogEntry::getComponentValues)
|
||||
.stream()
|
||||
.map(a -> a.stream()
|
||||
.map(ComponentLogEntryValue::getOriginalValue)
|
||||
.collect(Collectors.joining(", ")))
|
||||
.findFirst()
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,148 +0,0 @@
|
||||
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_RSS;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.client.redactionreportservice.RssReportClient;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentOverrideService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.RSSResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentsOverrides;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSFileResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSResponse;
|
||||
import com.iqser.red.service.redaction.report.v1.api.model.rss.DetailedRSSResponse;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnProperty(name = "application.rss.component-log.enabled", havingValue = "false")
|
||||
public class RSSController implements RSSResource {
|
||||
|
||||
private final RssReportClient rssReportClient;
|
||||
private final ComponentOverrideService componentOverrideService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public RSSResponse getRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId) {
|
||||
|
||||
return convert(rssReportClient.getRSS(dossierId, fileId));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
private RSSResponse convert(com.iqser.red.service.redaction.report.v1.api.model.rss.RSSResponse rssResponse) {
|
||||
|
||||
return new RSSResponse(rssResponse.getFiles()
|
||||
.stream()
|
||||
.map(this::convert)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
private RSSFileResponse convert(com.iqser.red.service.redaction.report.v1.api.model.rss.RSSFileResponse rssFileResponse) {
|
||||
|
||||
return new RSSFileResponse(rssFileResponse.getFilename(), rssFileResponse.getResult());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public DetailedRSSResponse getDetailedRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId) {
|
||||
|
||||
return rssReportClient.getDetailedRSS(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides) {
|
||||
|
||||
var rssReport = rssReportClient.getDetailedRSS(dossierId, fileId);
|
||||
var components = rssReport.getFiles()
|
||||
.get(0).getResult();
|
||||
|
||||
componentOverrideService.addOverrides(dossierId, fileId, componentsOverrides);
|
||||
|
||||
componentsOverrides.getComponentOverrides()
|
||||
.forEach((key, value) -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("The component is overwritten with value")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
"ComponentName",
|
||||
key,
|
||||
"Action",
|
||||
"MODIFY",
|
||||
"OriginalValue",
|
||||
components.get(key).getOriginalValue(),
|
||||
"OldValue",
|
||||
components.get(key).getValue() != null ? components.get(key)
|
||||
.getValue() : components.get(key).getOriginalValue(),
|
||||
"NewValue",
|
||||
value))
|
||||
.build()));
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
return componentOverrideService.getOverrides(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest) {
|
||||
|
||||
var rssReport = rssReportClient.getDetailedRSS(dossierId, fileId);
|
||||
var components = rssReport.getFiles()
|
||||
.get(0).getResult();
|
||||
|
||||
componentOverrideService.revertOverrides(dossierId, fileId, revertOverrideRequest);
|
||||
|
||||
revertOverrideRequest.getComponents()
|
||||
.forEach(component -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("The component override for was reverted")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
"ComponentName",
|
||||
component,
|
||||
"Action",
|
||||
"REVERT",
|
||||
"OriginalValue",
|
||||
components.get(component).getOriginalValue(),
|
||||
"OldValue",
|
||||
components.get(component).getValue() != null ? components.get(component)
|
||||
.getValue() : components.get(component).getOriginalValue(),
|
||||
"NewValue",
|
||||
components.get(component).getOriginalValue()))
|
||||
.build()));
|
||||
}
|
||||
|
||||
}
|
||||
@ -46,6 +46,7 @@ public class ReanalysisController implements ReanalysisResource {
|
||||
public void reanalyzeDossier(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = FORCE_PARAM, required = false, defaultValue = FALSE) boolean force) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
|
||||
reanalysisService.reanalyzeDossier(dossierId, force);
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
@ -117,11 +118,12 @@ public class ReanalysisController implements ReanalysisResource {
|
||||
@PreAuthorize("hasAuthority('" + REANALYZE_FILE + "')")
|
||||
public void ocrFile(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = FORCE_PARAM, required = false, defaultValue = FALSE) boolean force) {
|
||||
@RequestParam(value = FORCE_PARAM, required = false, defaultValue = FALSE) boolean force,
|
||||
@RequestParam(value = ALL_PAGES, required = false, defaultValue = FALSE) boolean allPages) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
validateOCR(dossierId, fileId);
|
||||
reanalysisService.ocrFile(dossierId, fileId, force);
|
||||
reanalysisService.ocrFile(dossierId, fileId, force, allPages);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierId)
|
||||
@ -139,7 +141,7 @@ public class ReanalysisController implements ReanalysisResource {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
fileIds.forEach(fileId -> validateOCR(dossierId, fileId));
|
||||
reanalysisService.ocrFiles(dossierId, fileIds);
|
||||
reanalysisService.ocrFiles(dossierId, fileIds, false);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierId)
|
||||
|
||||
@ -1,156 +0,0 @@
|
||||
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_REDACTION_LOG;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.service.FeignExceptionHandler.processFeignException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.RedactionLogResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.FilteredRedactionLogRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid;
|
||||
import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist;
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
|
||||
import feign.FeignException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Deprecated(forRemoval = true)
|
||||
public class RedactionLogController implements RedactionLogResource {
|
||||
|
||||
private final RedactionLogService redactionLogService;
|
||||
private final FileStatusService fileStatusService;
|
||||
private final FileManagementStorageService fileManagementStorageService;
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public RedactionLog getRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
|
||||
@RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions,
|
||||
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives) {
|
||||
|
||||
try {
|
||||
return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes);
|
||||
} catch (FeignException e) {
|
||||
throw processFeignException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public SectionGrid getSectionGrid(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
try {
|
||||
return redactionLogService.getSectionGrid(dossierId, fileId);
|
||||
} catch (FeignException e) {
|
||||
throw processFeignException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@SneakyThrows
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public ResponseEntity<?> getSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
try {
|
||||
return buildZipFileResponseEntity(fileId, dossierId, FileType.TEXT);
|
||||
} catch (FeignException e) {
|
||||
throw processFeignException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ResponseEntity<byte[]> buildZipFileResponseEntity(String fileId, String dossierId, FileType fileType) throws IOException {
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.parseMediaType("application/zip"));
|
||||
|
||||
var fileStatus = fileStatusService.getStatus(fileId);
|
||||
String filename = fileStatus.getFilename();
|
||||
if (filename != null) {
|
||||
var index = filename.lastIndexOf(".");
|
||||
String prefix = filename.substring(0, index);
|
||||
filename = prefix + ".json";
|
||||
httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=utf-8''" + StringEncodingUtils.urlEncode(prefix) + ".zip");
|
||||
}
|
||||
|
||||
byte[] zipBytes = getZippedBytes(dossierId, fileId, filename, fileType);
|
||||
httpHeaders.setContentLength(zipBytes.length);
|
||||
return new ResponseEntity<>(zipBytes, httpHeaders, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public RedactionLog getFilteredRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody FilteredRedactionLogRequest filteredRedactionLogRequest) {
|
||||
|
||||
try {
|
||||
|
||||
return redactionLogService.getFilteredRedactionLog(dossierId, fileId, filteredRedactionLogRequest);
|
||||
|
||||
} catch (FeignException e) {
|
||||
throw processFeignException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private byte[] getZippedBytes(String dossierId, String fileId, String filename, FileType fileType) throws IOException {
|
||||
|
||||
try {
|
||||
String objectId = dossierId + "/" + fileId + "." + fileType.name() + fileType.getExtension();
|
||||
|
||||
try (var inputStream = fileManagementStorageService.getObject(TenantContext.getTenantId(), objectId)) {
|
||||
byte[] input = inputStream.readAllBytes();
|
||||
inputStream.close();
|
||||
return zipBytes(filename, input);
|
||||
}
|
||||
|
||||
} catch (StorageObjectDoesNotExist e) {
|
||||
throw new RuntimeException(String.format("%s is not available", fileType.name()), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static byte[] zipBytes(String filename, byte[] input) throws IOException {
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(baos);
|
||||
ZipEntry entry = new ZipEntry(filename);
|
||||
entry.setSize(input.length);
|
||||
zos.putNextEntry(entry);
|
||||
zos.write(input);
|
||||
zos.closeEntry();
|
||||
zos.close();
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,8 +13,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
@ -30,18 +28,17 @@ import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.client.redactionreportservice.PlaceholderClient;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.client.redactionreportservice.ReportTemplatePlaceholderClient;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ReportTemplateService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierAttributeConfigPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileAttributeConfigPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ReportTemplatePersistenceService;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.ReportTemplateResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
@ -53,6 +50,8 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.ReportTemplateUploadRequest;
|
||||
import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist;
|
||||
import com.iqser.red.storage.commons.service.StorageService;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
|
||||
import feign.FeignException;
|
||||
@ -77,6 +76,7 @@ public class ReportTemplateController implements ReportTemplateResource {
|
||||
private final FileManagementStorageService fileManagementStorageService;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + GET_REPORT_TEMPLATES + "')")
|
||||
public List<ReportTemplate> getReportTemplatesByPlaceholder(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @RequestBody JSONPrimitive<String> placeholder) {
|
||||
@ -174,6 +174,7 @@ public class ReportTemplateController implements ReportTemplateResource {
|
||||
var storageId = reportTemplatePersistenceService.find(templateId).getStorageId();
|
||||
storageService.deleteObject(TenantContext.getTenantId(), storageId);
|
||||
reportTemplatePersistenceService.delete(templateId);
|
||||
reportTemplatePlaceholderClient.evictReportTemplateCache();
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(templateId)
|
||||
|
||||
@ -7,7 +7,6 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@ -24,20 +23,20 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.FileUploadException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.RulesValidationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.RulesValidationMapper;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.RulesResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsSyntaxValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RuleSyntaxErrorMessage;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RuleSyntaxWarningMessage;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequestModel;
|
||||
import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import feign.FeignException;
|
||||
@ -54,49 +53,32 @@ public class RulesController implements RulesResource {
|
||||
private final RulesPersistenceService rulesPersistenceService;
|
||||
private final RulesValidationService rulesValidationService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
private final FileStatusPersistenceService fileStatusPersistenceService;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public ResponseEntity<DroolsSyntaxValidationResponse> upload(@RequestBody RulesUploadRequestModel rules) {
|
||||
public ResponseEntity<DroolsValidationResponse> upload(@RequestBody RulesUploadRequestModel rules) {
|
||||
|
||||
RulesUploadRequest rulesUploadRequest = RulesUploadRequest.fromModel(rules);
|
||||
DroolsSyntaxValidationResponse droolsSyntaxValidationResponse = DroolsSyntaxValidationResponse.builder().build();
|
||||
try {
|
||||
DroolsSyntaxValidation droolsSyntaxValidation = rulesValidationService.validateRules(rulesUploadRequest.getRuleFileType(), rulesUploadRequest.getRules());
|
||||
var rulesSyntaxWarningMessages = droolsSyntaxValidation.getDroolsSyntaxDeprecatedWarnings()
|
||||
.stream()
|
||||
.map(warningMessage -> RuleSyntaxWarningMessage.builder()
|
||||
.line(warningMessage.getLine())
|
||||
.column(warningMessage.getColumn())
|
||||
.message(warningMessage.getMessage())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
droolsSyntaxValidationResponse.setRulesSyntaxWarningMessages(rulesSyntaxWarningMessages);
|
||||
if (!droolsSyntaxValidation.isCompiled()) {
|
||||
var rulesSyntaxErrorMessages = droolsSyntaxValidation.getDroolsSyntaxErrorMessages()
|
||||
.stream()
|
||||
.map(errorMessage -> RuleSyntaxErrorMessage.builder()
|
||||
.line(errorMessage.getLine())
|
||||
.column(errorMessage.getColumn())
|
||||
.message(errorMessage.getMessage())
|
||||
.build())
|
||||
.toList();
|
||||
droolsSyntaxValidationResponse.setRulesSyntaxErrorMessages(rulesSyntaxErrorMessages);
|
||||
if (!rules.isDryRun()) {
|
||||
return new ResponseEntity<>(droolsSyntaxValidationResponse, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
DroolsValidationResponse droolsValidationResponse = new DroolsValidationResponse();
|
||||
|
||||
if (rules.isDryRun()) {
|
||||
return ResponseEntity.ok(droolsSyntaxValidationResponse);
|
||||
try {
|
||||
var droolsValidation = rulesValidationService.validateRules(rulesUploadRequest.getRuleFileType(), rulesUploadRequest.getRules());
|
||||
droolsValidationResponse = RulesValidationMapper.createFromDroolsValidation(droolsValidation);
|
||||
if (!droolsValidation.isCompiled()) {
|
||||
|
||||
return new ResponseEntity<>(droolsValidationResponse, !rules.isDryRun() ? HttpStatus.UNPROCESSABLE_ENTITY : HttpStatus.OK);
|
||||
}
|
||||
} catch (FeignException e) {
|
||||
if (e.status() == HttpStatus.BAD_REQUEST.value()) {
|
||||
throw new BadRequestException("The provided rule string is not a valid drools rule file!");
|
||||
}
|
||||
}
|
||||
rulesPersistenceService.setRules(rulesUploadRequest.getRules(), rulesUploadRequest.getDossierTemplateId(), rulesUploadRequest.getRuleFileType());
|
||||
if (!rules.isDryRun()) {
|
||||
rulesPersistenceService.setRules(rulesUploadRequest.getRules(), rulesUploadRequest.getDossierTemplateId(), rulesUploadRequest.getRuleFileType());
|
||||
fileStatusPersistenceService.resetErrorCounter(rules.getDossierTemplateId());
|
||||
}
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
@ -105,7 +87,7 @@ public class RulesController implements RulesResource {
|
||||
.message(String.format("%s Rules have been updated", rulesUploadRequest.getRuleFileType()))
|
||||
.build());
|
||||
|
||||
return ResponseEntity.ok(droolsSyntaxValidationResponse);
|
||||
return new ResponseEntity<>(droolsValidationResponse, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@ -121,17 +103,20 @@ public class RulesController implements RulesResource {
|
||||
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
|
||||
public RulesResponse download(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType) {
|
||||
|
||||
var ruleEntity = rulesPersistenceService.getRules(dossierTemplateId, ruleFileType);
|
||||
return new RulesResponse(ruleEntity.getValue(), dossierTemplateId, ruleEntity.isTimeoutDetected());
|
||||
var ruleEntityOptional = rulesPersistenceService.getRules(dossierTemplateId, ruleFileType);
|
||||
if (ruleEntityOptional.isEmpty()) {
|
||||
throw new NotFoundException(String.format("No rule file of type %s found for dossierTemplateId %s", ruleFileType, dossierTemplateId));
|
||||
}
|
||||
return new RulesResponse(ruleEntityOptional.get().getValue(), dossierTemplateId, ruleEntityOptional.get().isTimeoutDetected());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public ResponseEntity<DroolsSyntaxValidationResponse> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@RequestParam(value = DRY_RUN_PARAMETER) boolean dryRun,
|
||||
@RequestPart(name = "file") MultipartFile file) {
|
||||
public ResponseEntity<DroolsValidationResponse> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@RequestParam(value = DRY_RUN_PARAMETER) boolean dryRun,
|
||||
@RequestPart(name = "file") MultipartFile file) {
|
||||
|
||||
return uploadFile(dossierTemplateId, RuleFileType.ENTITY, dryRun, file);
|
||||
}
|
||||
@ -139,10 +124,10 @@ public class RulesController implements RulesResource {
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public ResponseEntity<DroolsSyntaxValidationResponse> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType,
|
||||
@RequestParam(value = DRY_RUN_PARAMETER) boolean dryRun,
|
||||
@RequestPart(name = "file") MultipartFile file) {
|
||||
public ResponseEntity<DroolsValidationResponse> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType,
|
||||
@RequestParam(value = DRY_RUN_PARAMETER) boolean dryRun,
|
||||
@RequestPart(name = "file") MultipartFile file) {
|
||||
|
||||
try {
|
||||
return upload(new RulesUploadRequestModel(new String(file.getBytes(), StandardCharsets.UTF_8), dossierTemplateId, ruleFileType, dryRun));
|
||||
@ -175,4 +160,12 @@ public class RulesController implements RulesResource {
|
||||
return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public void unlockRules(String dossierTemplateId, RuleFileType ruleFileType) {
|
||||
|
||||
rulesPersistenceService.resetTimeoutDetected(dossierTemplateId, ruleFileType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,21 +14,29 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.acl.custom.dossier.DossierACLService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ApprovalVerificationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FilterByPermissionsService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
|
||||
@ -38,12 +46,17 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AddNotificationRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.notification.NotificationType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -64,6 +77,8 @@ public class StatusController implements StatusResource {
|
||||
private final AccessControlService accessControlService;
|
||||
private final NotificationPersistenceService notificationPersistenceService;
|
||||
private final DossierACLService dossierACLService;
|
||||
private final ApprovalVerificationService approvalVerificationService;
|
||||
private final FilterByPermissionsService filterByPermissionsService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -79,6 +94,28 @@ public class StatusController implements StatusResource {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_FILE_STATUS + "')")
|
||||
public JSONPrimitive<Map<String, List<FileStatus>>> getFilesByIds(@RequestBody JSONPrimitive<Map<String, Set<String>>> filesByDossier) {
|
||||
|
||||
// filter dossiers by view
|
||||
var accessibleDossierIds = filterByPermissionsService.onlyViewableDossierIds(new ArrayList<>(filesByDossier.getValue().keySet()));
|
||||
var response = new HashMap<String, List<FileStatus>>();
|
||||
for (var dossierId : accessibleDossierIds) {
|
||||
var allFoundFiles = fileStatusManagementService.findAllDossierIdAndIds(dossierId,
|
||||
filesByDossier.getValue()
|
||||
.get(dossierId));
|
||||
response.put(dossierId,
|
||||
allFoundFiles.stream()
|
||||
.map(FileStatusMapper::toFileStatus)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return new JSONPrimitive<>(response);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_FILE_STATUS + "')")
|
||||
public Map<String, List<FileStatus>> getDossierStatus(@RequestBody List<String> dossierIds) {
|
||||
@ -299,31 +336,44 @@ public class StatusController implements StatusResource {
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + SET_STATUS_APPROVED + "')")
|
||||
public void setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
public ApproveResponse setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force) {
|
||||
|
||||
accessControlService.checkAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
setStatusApprovedForFile(dossierId, fileId);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Document status was changed to Approved")
|
||||
.details(Map.of(DOSSIER_ID, dossierId))
|
||||
.build());
|
||||
|
||||
var dossier = dossierACLService.enhanceDossierWithACLData(dossierManagementService.getDossierById(dossierId, false, false));
|
||||
if (!dossier.getOwnerId().equals(KeycloakSecurity.getUserId())) {
|
||||
|
||||
var fileStatus = fileStatusManagementService.getFileStatus(fileId);
|
||||
|
||||
notificationPersistenceService.insertNotification(AddNotificationRequest.builder()
|
||||
.userId(dossier.getOwnerId())
|
||||
.issuerId(KeycloakSecurity.getUserId())
|
||||
.notificationType(NotificationType.DOCUMENT_APPROVED.name())
|
||||
.target(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, FILE_NAME, fileStatus.getFilename()))
|
||||
.build());
|
||||
ApproveResponse approveResponse = new ApproveResponse(fileId, false, new ArrayList<>());
|
||||
if (!force) {
|
||||
approveResponse = approvalVerificationService.verifyApprovalOfFile(dossierId, fileId);
|
||||
}
|
||||
if (!approveResponse.isHasWarnings()) {
|
||||
setStatusApprovedForFile(dossierId, fileId);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Document status was changed to Approved")
|
||||
.details(Map.of(DOSSIER_ID, dossierId))
|
||||
.build());
|
||||
|
||||
var dossier = dossierACLService.enhanceDossierWithACLData(dossierManagementService.getDossierById(dossierId, false, false));
|
||||
|
||||
if (dossier.getOwnerId() == null) {
|
||||
throw new ConflictException("Dossier has no owner!");
|
||||
}
|
||||
if (!dossier.getOwnerId().equals(KeycloakSecurity.getUserId())) {
|
||||
|
||||
var fileStatus = fileStatusManagementService.getFileStatus(fileId);
|
||||
|
||||
notificationPersistenceService.insertNotification(AddNotificationRequest.builder()
|
||||
.userId(dossier.getOwnerId())
|
||||
.issuerId(KeycloakSecurity.getUserId())
|
||||
.notificationType(NotificationType.DOCUMENT_APPROVED.name())
|
||||
.target(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, FILE_NAME, fileStatus.getFilename()))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
return approveResponse;
|
||||
}
|
||||
|
||||
|
||||
@ -357,8 +407,10 @@ public class StatusController implements StatusResource {
|
||||
|
||||
private void generatePossibleUnassignedFromFileNotification(String dossierId, String fileId, FileModel oldFileStatus, String newAssigneeId) {
|
||||
|
||||
if (oldFileStatus.getAssignee() == null || newAssigneeId == null || oldFileStatus.getAssignee().equals(newAssigneeId) || KeycloakSecurity.getUserId()
|
||||
.equals(oldFileStatus.getAssignee())) {
|
||||
if (oldFileStatus.getAssignee() == null
|
||||
|| newAssigneeId == null && oldFileStatus.getAssignee() == null
|
||||
|| oldFileStatus.getAssignee().equals(newAssigneeId)
|
||||
|| KeycloakSecurity.getUserId().equals(oldFileStatus.getAssignee())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -398,14 +450,22 @@ public class StatusController implements StatusResource {
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + SET_STATUS_APPROVED + "')")
|
||||
public void setStatusApprovedForList(String dossierId, List<String> fileIds) {
|
||||
public List<ApproveResponse> setStatusApprovedForList(String dossierId,
|
||||
List<String> fileIds,
|
||||
@RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force) {
|
||||
|
||||
List<ApproveResponse> approveResponses = new ArrayList<>();
|
||||
accessControlService.checkAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
|
||||
dossierManagementService.getDossierById(dossierId, false, false);
|
||||
|
||||
fileIds.forEach(fileId -> setStatusApproved(dossierId, fileId));
|
||||
if (fileIds.size() > 50) {
|
||||
throw new BadRequestException("Maximum amount of files that can be approved at once is 50.");
|
||||
}
|
||||
|
||||
fileIds.forEach(fileId -> approveResponses.add(setStatusApproved(dossierId, fileId, force)));
|
||||
return approveResponses;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,176 @@
|
||||
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.IMPORT_FILES;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.USE_SUPPORT_CONTROLLER;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.dataexchange.service.DatasetExchangeService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.dataexchange.service.FileExchangeImportService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.migration.MigrationController;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ReanalysisService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.dataexchange.service.FileExchangeExportService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.ImportResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.ReanalysisSettings;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.SupportResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DownloadResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatusFilter;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileExchangeExportRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.ReanalyzeFilesResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@PreAuthorize("hasAuthority('" + USE_SUPPORT_CONTROLLER + "')")
|
||||
public class SupportController implements SupportResource {
|
||||
|
||||
private final ReanalysisService reanalysisService;
|
||||
private final FileStatusManagementService fileStatusManagementService;
|
||||
private final FileExchangeExportService fileExchangeExportService;
|
||||
private final FileExchangeImportService fileExchangeImportService;
|
||||
private final DatasetExchangeService datasetExchangeService;
|
||||
|
||||
|
||||
@Override
|
||||
public ReanalyzeFilesResponse reanalyzeFiles(String dossierTemplateId, ReanalysisSettings reanalysisSettings) {
|
||||
|
||||
return new ReanalyzeFilesResponse(reanalysisService.reanalyzeTemplate(dossierTemplateId, reanalysisSettings));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void reanalyzeAllRelevantErrorFiles(@RequestParam(value = FULL_REANALYSIS_PARAM, required = false, defaultValue = FALSE) boolean repeatStructureAnalysis,
|
||||
@RequestParam(value = RUN_OCR_PARAM, required = false, defaultValue = FALSE) boolean runOcr) {
|
||||
|
||||
reanalysisService.reanalyzeAllRelevantErrorFiles(repeatStructureAnalysis, runOcr);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void reanalyzeErrorFilesBulkForDossier(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@RequestBody List<String> fileIds,
|
||||
@RequestParam(value = FULL_REANALYSIS_PARAM, required = false, defaultValue = FALSE) boolean repeatStructureAnalysis,
|
||||
@RequestParam(value = RUN_OCR_PARAM, required = false, defaultValue = FALSE) boolean runOcr) {
|
||||
|
||||
reanalysisService.reanalyzeGivenErrorFilesInDossier(dossierId, new HashSet<>(fileIds), repeatStructureAnalysis, runOcr);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static Predicate<FileModel> matchesStatusFilters(FileStatusFilter fileStatusFilter) {
|
||||
|
||||
FileStatusFilter filter = Optional.ofNullable(fileStatusFilter)
|
||||
.orElseGet(FileStatusFilter::new);
|
||||
|
||||
if (filter.getProcessingStatusList() == null) {
|
||||
filter.setProcessingStatusList(new ArrayList<>());
|
||||
}
|
||||
|
||||
if (filter.getWorkflowStatusList() == null) {
|
||||
filter.setWorkflowStatusList(new ArrayList<>());
|
||||
}
|
||||
|
||||
return fileStatus -> (filter.getProcessingStatusList().isEmpty() || filter.getProcessingStatusList().contains(fileStatus.getProcessingStatus()))
|
||||
&& (filter.getWorkflowStatusList().isEmpty() || filter.getWorkflowStatusList().contains(fileStatus.getWorkflowStatus()))
|
||||
&& (filter.isIncludeSoftDeletedFiles() || fileStatus.getDeleted() == null)
|
||||
&& (filter.isIncludeHardDeletedFiles() || fileStatus.getHardDeletedTime() == null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<FileStatus> getFileStatus(@RequestBody FileStatusFilter fileStatusFilter) {
|
||||
|
||||
return fileStatusManagementService.getAllFileStatuses()
|
||||
.stream()
|
||||
.filter(matchesStatusFilters(fileStatusFilter))
|
||||
.map(FileStatusMapper::toFileStatus)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<FileStatus> getFileStatusForDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @RequestBody FileStatusFilter fileStatusFilter) {
|
||||
|
||||
return fileStatusManagementService.getAllDossierTemplateStatus(dossierTemplateId)
|
||||
.stream()
|
||||
.filter(matchesStatusFilters(fileStatusFilter))
|
||||
.map(FileStatusMapper::toFileStatus)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<FileStatus> exportFiles(@PathVariable(DOSSIER_ID) String dossierId, @RequestBody FileStatusFilter fileStatusFilter) {
|
||||
|
||||
return fileStatusManagementService.getAllDossierStatus(dossierId)
|
||||
.stream()
|
||||
.filter(matchesStatusFilters(fileStatusFilter))
|
||||
.map(FileStatusMapper::toFileStatus)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DownloadResponse exportDataset(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId) {
|
||||
|
||||
return datasetExchangeService.prepareExport(dossierTemplateId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DownloadResponse exportFiles(String dossierTemplateId, FileExchangeExportRequest exportRequest) {
|
||||
|
||||
return fileExchangeExportService.prepareExportDownload(dossierTemplateId, exportRequest);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + IMPORT_FILES + "')")
|
||||
public ImportResponse importFiles(MultipartFile file) {
|
||||
|
||||
byte[] bytes;
|
||||
try {
|
||||
bytes = file.getBytes();
|
||||
} catch (IOException e) {
|
||||
throw new BadRequestException("File could not be read and is likely corrupted.", e);
|
||||
}
|
||||
return fileExchangeImportService.importFileExchangeArchive(KeycloakSecurity.getUserId(), bytes);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + IMPORT_FILES + "')")
|
||||
public ImportResponse importDataset(MultipartFile file) {
|
||||
|
||||
byte[] bytes;
|
||||
try {
|
||||
bytes = file.getBytes();
|
||||
} catch (IOException e) {
|
||||
throw new BadRequestException("File could not be read and is likely corrupted.", e);
|
||||
}
|
||||
return datasetExchangeService.importDataset(KeycloakSecurity.getUserId(), bytes);
|
||||
}
|
||||
|
||||
}
|
||||
@ -23,12 +23,11 @@ import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileFormatValidationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.ByteContentDocument;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileFormatValidationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ReanalysisService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.UploadService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
@ -37,10 +36,12 @@ import com.iqser.red.service.persistence.service.v1.api.external.resource.Upload
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileUploadResult;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
|
||||
import feign.FeignException;
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
@ -52,9 +53,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@SuppressWarnings("PMD")
|
||||
public class UploadController implements UploadResource {
|
||||
|
||||
private static final int THRESHOLD_ENTRIES = 10000;
|
||||
private static final int THRESHOLD_SIZE = 1000000000; // 1 GB
|
||||
private static final double THRESHOLD_RATIO = 10;
|
||||
private static final int THRESHOLD_ENTRIES = 10000; // Maximum number of files allowed
|
||||
private static final int THRESHOLD_SIZE = 1000000000; // 1 GB total unzipped data
|
||||
private static final double THRESHOLD_RATIO = 10; // Max allowed compression ratio
|
||||
|
||||
private final UploadService uploadService;
|
||||
private final ReanalysisService reanalysisService;
|
||||
@ -67,34 +68,29 @@ public class UploadController implements UploadResource {
|
||||
@Override
|
||||
public FileUploadResult upload(@RequestPart(name = "file") MultipartFile file,
|
||||
@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@RequestParam(value = "keepManualRedactions", required = false, defaultValue = "false") boolean keepManualRedactions) {
|
||||
@RequestParam(value = "keepManualRedactions", required = false, defaultValue = "false") boolean keepManualRedactions,
|
||||
@Parameter(name = DISABLE_AUTOMATIC_ANALYSIS_PARAM, description = "Disables automatic redaction for the uploaded file, imports only imported redactions") @RequestParam(value = DISABLE_AUTOMATIC_ANALYSIS_PARAM, required = false, defaultValue = "false") boolean disableAutomaticAnalysis) {
|
||||
|
||||
accessControlService.checkAccessPermissionsToDossier(dossierId);
|
||||
if (file.getOriginalFilename() == null) {
|
||||
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
if (originalFilename == null) {
|
||||
throw new BadRequestException("Could not upload file, no filename provided.");
|
||||
}
|
||||
|
||||
var extension = getExtension(file.getOriginalFilename());
|
||||
|
||||
String extension = getExtension(originalFilename);
|
||||
try {
|
||||
switch (extension) {
|
||||
case "zip":
|
||||
return handleZip(dossierId, file.getBytes(), keepManualRedactions);
|
||||
case "csv":
|
||||
return uploadService.importCsv(dossierId, file.getBytes());
|
||||
default:
|
||||
if (!fileFormatValidationService.getAllFileFormats().contains(extension)) {
|
||||
throw new BadRequestException("Invalid file uploaded");
|
||||
}
|
||||
if (!fileFormatValidationService.getValidFileFormatsForTenant(TenantContext.getTenantId()).contains(extension)) {
|
||||
throw new NotAllowedException("Insufficient permissions");
|
||||
}
|
||||
return uploadService.processSingleFile(dossierId, file.getOriginalFilename(), file.getBytes(), keepManualRedactions);
|
||||
}
|
||||
return switch (extension) {
|
||||
case "zip" -> handleZip(dossierId, file.getBytes(), keepManualRedactions, disableAutomaticAnalysis);
|
||||
case "csv" -> uploadService.importCsv(dossierId, file.getBytes());
|
||||
default -> {
|
||||
validateExtensionOrThrow(extension);
|
||||
yield uploadService.processSingleFile(dossierId, originalFilename, file.getBytes(), keepManualRedactions, disableAutomaticAnalysis);
|
||||
}
|
||||
};
|
||||
} catch (IOException e) {
|
||||
throw new BadRequestException(e.getMessage(), e);
|
||||
throw new BadRequestException("Failed to process file: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -109,7 +105,6 @@ public class UploadController implements UploadResource {
|
||||
accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId);
|
||||
|
||||
try {
|
||||
|
||||
reanalysisService.importRedactions(ByteContentDocument.builder().dossierId(dossierId).fileId(fileId).document(file.getBytes()).pages(pageInclusionRequest).build());
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
@ -120,84 +115,116 @@ public class UploadController implements UploadResource {
|
||||
.details(Map.of("dossierId", dossierId))
|
||||
.build());
|
||||
} catch (IOException e) {
|
||||
throw new BadRequestException(e.getMessage(), e);
|
||||
throw new BadRequestException("Failed to import redactions: " + e.getMessage(), e);
|
||||
} catch (FeignException e) {
|
||||
throw processFeignException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getExtension(String fileName) {
|
||||
private void validateExtensionOrThrow(String extension) {
|
||||
|
||||
return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(Locale.ROOT);
|
||||
if (!fileFormatValidationService.getAllFileFormats().contains(extension)) {
|
||||
throw new BadRequestException("Invalid file uploaded (unrecognized extension).");
|
||||
}
|
||||
if (!fileFormatValidationService.getValidFileFormatsForTenant(TenantContext.getTenantId()).contains(extension)) {
|
||||
throw new NotAllowedException("Insufficient permissions for this file type.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private FileUploadResult handleZip(String dossierId, byte[] fileContent, boolean keepManualRedactions) throws IOException {
|
||||
/**
|
||||
* 1. Write the uploaded content to a temp ZIP file
|
||||
* 2. Check the number of entries and reject if too big or if symlinks found
|
||||
* 3. Unzip and process each file, while checking size and ratio.
|
||||
*/
|
||||
private FileUploadResult handleZip(String dossierId, byte[] fileContent, boolean keepManualRedactions, boolean disableAutomaticAnalysis) throws IOException {
|
||||
|
||||
File tempFile = FileUtils.createTempFile(UUID.randomUUID().toString(), ".zip");
|
||||
try (var fileOutputStream = new FileOutputStream(tempFile)) {
|
||||
IOUtils.write(fileContent, fileOutputStream);
|
||||
File tempZip = FileUtils.createTempFile(UUID.randomUUID().toString(), ".zip");
|
||||
try (FileOutputStream fos = new FileOutputStream(tempZip)) {
|
||||
IOUtils.write(fileContent, fos);
|
||||
}
|
||||
|
||||
try {
|
||||
checkForSymlinks(tempFile);
|
||||
validateZipEntries(tempZip);
|
||||
|
||||
var zipData = unzip(tempFile, dossierId, keepManualRedactions);
|
||||
try {
|
||||
ZipData zipData = processZipContents(tempZip, dossierId, keepManualRedactions, disableAutomaticAnalysis);
|
||||
|
||||
if (zipData.csvBytes != null) {
|
||||
try {
|
||||
var importResult = uploadService.importCsv(dossierId, zipData.csvBytes);
|
||||
zipData.fileUploadResult.getProcessedAttributes().addAll(importResult.getProcessedAttributes());
|
||||
zipData.fileUploadResult.getProcessedFileIds().addAll(importResult.getProcessedFileIds());
|
||||
FileUploadResult csvResult = uploadService.importCsv(dossierId, zipData.csvBytes);
|
||||
zipData.fileUploadResult.getProcessedAttributes().addAll(csvResult.getProcessedAttributes());
|
||||
zipData.fileUploadResult.getProcessedFileIds().addAll(csvResult.getProcessedFileIds());
|
||||
} catch (Exception e) {
|
||||
log.debug("CSV file inside ZIP failed", e);
|
||||
// TODO return un-processed files to client
|
||||
log.debug("CSV file inside ZIP failed to import", e);
|
||||
}
|
||||
} else if (zipData.fileUploadResult.getFileIds().isEmpty()) {
|
||||
if (zipData.containedUnpermittedFiles) {
|
||||
throw new NotAllowedException("Zip file contains unpermitted files");
|
||||
throw new NotAllowedException("Zip file contains unpermitted files.");
|
||||
} else {
|
||||
throw new BadRequestException("Only unsupported files in zip file");
|
||||
throw new BadRequestException("Only unsupported files in the ZIP.");
|
||||
}
|
||||
}
|
||||
|
||||
return zipData.fileUploadResult;
|
||||
|
||||
} finally {
|
||||
boolean isDeleted = tempFile.delete();
|
||||
if (!isDeleted) {
|
||||
log.warn("tempFile could not be deleted");
|
||||
|
||||
if (!tempZip.delete()) {
|
||||
log.warn("Could not delete temporary ZIP file: {}", tempZip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkForSymlinks(File tempFile) throws IOException {
|
||||
private void validateZipEntries(File tempZip) throws IOException {
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(tempZip); ZipFile zipFile = new ZipFile(fis.getChannel())) {
|
||||
|
||||
int count = 0;
|
||||
var entries = zipFile.getEntries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipArchiveEntry ze = entries.nextElement();
|
||||
|
||||
try (var fis = new FileInputStream(tempFile); var zipFile = new ZipFile(fis.getChannel())) {
|
||||
for (var entryEnum = zipFile.getEntries(); entryEnum.hasMoreElements(); ) {
|
||||
var ze = entryEnum.nextElement();
|
||||
if (ze.isUnixSymlink()) {
|
||||
throw new BadRequestException("ZIP-files with symlinks are not allowed");
|
||||
throw new BadRequestException("ZIP-files with symlinks are not allowed.");
|
||||
}
|
||||
|
||||
if (!ze.isDirectory() && !ze.getName().startsWith(".")) {
|
||||
count++;
|
||||
if (count > THRESHOLD_ENTRIES) {
|
||||
throw new BadRequestException("ZIP-Bomb detected: too many entries.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ZipData unzip(File tempFile, String dossierId, boolean keepManualRedactions) throws IOException {
|
||||
private ZipData processZipContents(File tempZip, String dossierId, boolean keepManualRedactions, boolean disableAutomaticAnalysis) throws IOException {
|
||||
|
||||
var zipData = new ZipData();
|
||||
ZipData zipData = new ZipData();
|
||||
|
||||
try (var fis = new FileInputStream(tempFile); var zipFile = new ZipFile(fis.getChannel())) {
|
||||
try (FileInputStream fis = new FileInputStream(tempZip); ZipFile zipFile = new ZipFile(fis.getChannel())) {
|
||||
|
||||
for (var entryEnum = zipFile.getEntries(); entryEnum.hasMoreElements(); ) {
|
||||
var ze = entryEnum.nextElement();
|
||||
zipData.totalEntryArchive++;
|
||||
var entries = zipFile.getEntries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipArchiveEntry entry = entries.nextElement();
|
||||
|
||||
if (!ze.isDirectory()) {
|
||||
processFileZipEntry(ze, zipFile, dossierId, keepManualRedactions, zipData);
|
||||
if (entry.isDirectory() || entry.getName().startsWith(".")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
byte[] entryBytes = readEntryWithRatioCheck(entry, zipFile);
|
||||
zipData.totalSizeArchive += entryBytes.length;
|
||||
if (zipData.totalSizeArchive > THRESHOLD_SIZE) {
|
||||
throw new BadRequestException("ZIP-Bomb detected (exceeds total size limit).");
|
||||
}
|
||||
|
||||
String extension = getExtension(entry.getName());
|
||||
if ("csv".equalsIgnoreCase(extension)) {
|
||||
zipData.csvBytes = entryBytes;
|
||||
} else {
|
||||
handleRegularFile(dossierId, entryBytes, extension, extractFileName(entry.getName()), zipData, keepManualRedactions, disableAutomaticAnalysis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -205,73 +232,70 @@ public class UploadController implements UploadResource {
|
||||
}
|
||||
|
||||
|
||||
private void processFileZipEntry(ZipArchiveEntry ze, ZipFile zipFile, String dossierId, boolean keepManualRedactions, ZipData zipData) throws IOException {
|
||||
private byte[] readEntryWithRatioCheck(ZipArchiveEntry entry, ZipFile zipFile) throws IOException {
|
||||
|
||||
var extension = getExtension(ze.getName());
|
||||
long compressedSize = entry.getCompressedSize() > 0 ? entry.getCompressedSize() : 1;
|
||||
try (var is = zipFile.getInputStream(entry); var bos = new ByteArrayOutputStream()) {
|
||||
|
||||
final String fileName;
|
||||
if (ze.getName().lastIndexOf("/") >= 0) {
|
||||
fileName = ze.getName().substring(ze.getName().lastIndexOf("/") + 1);
|
||||
} else {
|
||||
fileName = ze.getName();
|
||||
}
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
int totalUncompressed = 0;
|
||||
|
||||
if (fileName.startsWith(".")) {
|
||||
return;
|
||||
}
|
||||
while ((bytesRead = is.read(buffer)) != -1) {
|
||||
bos.write(buffer, 0, bytesRead);
|
||||
totalUncompressed += bytesRead;
|
||||
|
||||
var entryAsBytes = readCurrentZipEntry(ze, zipFile);
|
||||
zipData.totalSizeArchive += entryAsBytes.length;
|
||||
|
||||
// 1. the uncompressed data size is too much for the application resource capacity
|
||||
// 2. too many entries in the archive can lead to inode exhaustion of the file-system
|
||||
if (zipData.totalSizeArchive > THRESHOLD_SIZE || zipData.totalEntryArchive > THRESHOLD_ENTRIES) {
|
||||
throw new BadRequestException("ZIP-Bomb detected.");
|
||||
}
|
||||
|
||||
if ("csv".equals(extension)) {
|
||||
zipData.csvBytes = entryAsBytes;
|
||||
} else if (fileFormatValidationService.getAllFileFormats().contains(extension)) {
|
||||
|
||||
if (!fileFormatValidationService.getValidFileFormatsForTenant(TenantContext.getTenantId()).contains(extension)) {
|
||||
zipData.containedUnpermittedFiles = true;
|
||||
return;
|
||||
}
|
||||
zipData.containedUnpermittedFiles = false;
|
||||
|
||||
try {
|
||||
var result = uploadService.processSingleFile(dossierId, fileName, entryAsBytes, keepManualRedactions);
|
||||
zipData.fileUploadResult.getFileIds().addAll(result.getFileIds());
|
||||
} catch (Exception e) {
|
||||
log.debug("PDF File inside ZIP failed", e);
|
||||
// TODO return un-processed files to client
|
||||
double ratio = (double) totalUncompressed / compressedSize;
|
||||
if (ratio > THRESHOLD_RATIO) {
|
||||
throw new BadRequestException("ZIP-Bomb detected (compression ratio too high).");
|
||||
}
|
||||
}
|
||||
return bos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private byte[] readCurrentZipEntry(ZipArchiveEntry ze, ZipFile zipFile) throws IOException {
|
||||
private void handleRegularFile(String dossierId,
|
||||
byte[] fileBytes,
|
||||
String extension,
|
||||
String fileName,
|
||||
ZipData zipData,
|
||||
boolean keepManualRedactions,
|
||||
boolean disableAutomaticAnalysis) {
|
||||
|
||||
var bos = new ByteArrayOutputStream();
|
||||
|
||||
try (var entryStream = zipFile.getInputStream(ze)) {
|
||||
var buffer = new byte[2048];
|
||||
var nBytes = 0;
|
||||
int totalSizeEntry = 0;
|
||||
|
||||
while ((nBytes = entryStream.read(buffer)) > 0) {
|
||||
bos.write(buffer, 0, nBytes);
|
||||
totalSizeEntry += nBytes;
|
||||
|
||||
double compressionRatio = (float) totalSizeEntry / ze.getCompressedSize();
|
||||
if (compressionRatio > THRESHOLD_RATIO) {
|
||||
// ratio between compressed and uncompressed data is highly suspicious, looks like a Zip Bomb Attack
|
||||
throw new BadRequestException("ZIP-Bomb detected.");
|
||||
}
|
||||
}
|
||||
if (!fileFormatValidationService.getAllFileFormats().contains(extension)) {
|
||||
zipData.containedUnpermittedFiles = false;
|
||||
return;
|
||||
}
|
||||
|
||||
return bos.toByteArray();
|
||||
if (!fileFormatValidationService.getValidFileFormatsForTenant(TenantContext.getTenantId()).contains(extension)) {
|
||||
zipData.containedUnpermittedFiles = true;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
FileUploadResult result = uploadService.processSingleFile(dossierId, fileName, fileBytes, keepManualRedactions, disableAutomaticAnalysis);
|
||||
zipData.fileUploadResult.getFileIds().addAll(result.getFileIds());
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to process file '{}' in ZIP: {}", fileName, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String extractFileName(String path) {
|
||||
|
||||
int idx = path.lastIndexOf('/');
|
||||
return (idx >= 0) ? path.substring(idx + 1) : path;
|
||||
}
|
||||
|
||||
|
||||
private String getExtension(String fileName) {
|
||||
|
||||
int idx = fileName.lastIndexOf('.');
|
||||
if (idx < 0) {
|
||||
return "";
|
||||
}
|
||||
return fileName.substring(idx + 1).toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
|
||||
@ -280,7 +304,6 @@ public class UploadController implements UploadResource {
|
||||
|
||||
byte[] csvBytes;
|
||||
int totalSizeArchive;
|
||||
int totalEntryArchive;
|
||||
FileUploadResult fileUploadResult = new FileUploadResult();
|
||||
boolean containedUnpermittedFiles;
|
||||
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_USER_STATS;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.acl.custom.dossier.DossierACLService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.UserStatsResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.UserStats;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class UserStatsController implements UserStatsResource {
|
||||
|
||||
private final UserService userService;
|
||||
private final DossierService dossierService;
|
||||
private final FileStatusPersistenceService fileStatusPersistenceService;
|
||||
private final DossierACLService dossierACLService;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_USER_STATS + "')")
|
||||
public ResponseEntity<UserStats> getUserStats(String userId) {
|
||||
|
||||
if (userService.getUserById(userId).isEmpty()) {
|
||||
throw new NotFoundException(String.format("The user with id %s is not found.", userId));
|
||||
}
|
||||
List<String> dossierMemberships = new ArrayList<>();
|
||||
List<String> dossierOwnerships = new ArrayList<>();
|
||||
dossierService.getAllDossiers()
|
||||
.stream()
|
||||
.filter(dossierEntity -> dossierEntity.getHardDeletedTime() == null)
|
||||
.forEach(d -> {
|
||||
if (dossierACLService.getMembers(d.getId()).contains(userId)) {
|
||||
dossierMemberships.add(d.getId());
|
||||
}
|
||||
if (dossierACLService.getOwners(d.getId()).contains(userId)) {
|
||||
dossierOwnerships.add(d.getId());
|
||||
}
|
||||
});
|
||||
|
||||
return new ResponseEntity<>(new UserStats(dossierMemberships.size(), dossierOwnerships.size(), this.fileStatusPersistenceService.getNumberOfAssignedFiles(userId)),
|
||||
HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.VersionsResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
|
||||
@ -27,6 +28,7 @@ public class VersionsController implements VersionsResource {
|
||||
private final DictionaryPersistenceService dictionaryPersistenceService;
|
||||
private final RulesPersistenceService rulesPersistenceService;
|
||||
private final AccessControlService accessControlService;
|
||||
private final LegalBasisMappingPersistenceService legalBasisMappingPersistenceService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -35,7 +37,9 @@ public class VersionsController implements VersionsResource {
|
||||
|
||||
var result = new HashMap<String, VersionsResponse>();
|
||||
dossierTemplateIds.forEach(rsId -> {
|
||||
VersionsResponse response = new VersionsResponse(dictionaryPersistenceService.getVersion(rsId), rulesPersistenceService.getVersion(rsId, RuleFileType.ENTITY));
|
||||
VersionsResponse response = new VersionsResponse(dictionaryPersistenceService.getVersion(rsId),
|
||||
rulesPersistenceService.getVersion(rsId, RuleFileType.ENTITY),
|
||||
legalBasisMappingPersistenceService.getVersion(rsId));
|
||||
result.put(rsId, response);
|
||||
});
|
||||
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
plugins {
|
||||
id("com.iqser.red.service.java-conventions")
|
||||
id("io.freefair.lombok") version "8.4"
|
||||
id("io.freefair.lombok") version "8.6"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":persistence-service-processor-v1"))
|
||||
api(project(":persistence-service-external-api-v2"))
|
||||
api(project(":persistence-service-external-api-impl-v1"))
|
||||
|
||||
implementation("org.mapstruct:mapstruct:1.5.5.Final")
|
||||
annotationProcessor("org.mapstruct:mapstruct-processor:1.5.5.Final")
|
||||
}
|
||||
|
||||
description = "persistence-service-external-api-impl-v2"
|
||||
|
||||
@ -1,31 +1,49 @@
|
||||
package com.iqser.red.persistence.service.v2.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_RSS;
|
||||
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource.DOSSIER_ID_PARAM;
|
||||
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_ID_PARAM;
|
||||
import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_ID_PARAM;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.StatusController;
|
||||
import com.iqser.red.persistence.service.v2.external.api.impl.mapper.ComponentMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentLogService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.CurrentApplicationTypeProvider;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntityReference;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.users.model.User;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.BulkComponentsRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.Component;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentValue;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.EntityReference;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentOverrideList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponentsList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.resource.ComponentResource;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.knecon.fforesight.tenantcommons.TenantProvider;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -34,13 +52,21 @@ import lombok.experimental.FieldDefaults;
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "4. Component endpoints", description = "Provides operations related to components")
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class ComponentControllerV2 implements ComponentResource {
|
||||
|
||||
DossierTemplateController dossierTemplateController;
|
||||
ComponentLogService componentLogService;
|
||||
StatusController statusController;
|
||||
FileStatusService fileStatusService;
|
||||
private final AccessControlService accessControlService;
|
||||
private final ComponentLogService componentLogService;
|
||||
private final UserService userService;
|
||||
private final StatusController statusController;
|
||||
private final FileStatusService fileStatusService;
|
||||
private final DossierController dossierController;
|
||||
private final DossierTemplatePersistenceService dossierTemplatePersistenceService;
|
||||
private final CurrentApplicationTypeProvider currentApplicationTypeProvider;
|
||||
private final ComponentMapper componentMapper = ComponentMapper.INSTANCE;
|
||||
|
||||
|
||||
@Value("${documine.components.filesLimit:100}")
|
||||
private int documineComponentsFilesLimit = 100;
|
||||
|
||||
|
||||
@Override
|
||||
@ -49,68 +75,25 @@ public class ComponentControllerV2 implements ComponentResource {
|
||||
@PathVariable(FILE_ID_PARAM) String fileId,
|
||||
@RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails) {
|
||||
|
||||
dossierTemplateController.getDossierTemplate(dossierTemplateId);
|
||||
var componentLog = componentLogService.getComponentLog(dossierId, fileId, true);
|
||||
checkApplicationType();
|
||||
validateUserRoles(KeycloakSecurity.getUserId());
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
var componentLog = componentLogService.getComponentLog(dossierId, fileId);
|
||||
|
||||
Map<String, List<String>> basicComponent = new LinkedHashMap<>();
|
||||
for (ComponentLogEntry componentLogEntry : componentLog.getComponentLogEntries()) {
|
||||
basicComponent.put(componentLogEntry.getName(),
|
||||
componentLogEntry.getComponentValues()
|
||||
.stream()
|
||||
.map(ComponentLogEntryValue::getValue)
|
||||
.toList());
|
||||
}
|
||||
return componentMapper.toFileComponents(componentLog, dossierTemplateId, dossierId, fileId, fileStatusService.getFileName(fileId), includeDetails);
|
||||
}
|
||||
|
||||
Map<String, Component> componentsDetails = new LinkedHashMap<>();
|
||||
if (includeDetails) {
|
||||
for (ComponentLogEntry entry : componentLog.getComponentLogEntries()) {
|
||||
componentsDetails.put(entry.getName(), Component.builder().name(entry.getName()).componentValues(toComponentList(entry)).build());
|
||||
|
||||
private void validateUserRoles(String userId) {
|
||||
|
||||
Optional<User> userOptional = userService.getUserById(userId);
|
||||
if (userOptional.isPresent()) {
|
||||
if (userOptional.get().getRoles()
|
||||
.stream()
|
||||
.noneMatch(ApplicationRoles.VALID_MEMBER_ROLES::contains)) {
|
||||
throw new NotAllowedException("User doesn't have appropriate roles");
|
||||
}
|
||||
}
|
||||
|
||||
return FileComponents.builder()
|
||||
.dossierTemplateId(dossierTemplateId)
|
||||
.dossierId(dossierId)
|
||||
.filename(fileStatusService.getFileName(fileId))
|
||||
.fileId(fileId)
|
||||
.components(basicComponent)
|
||||
.componentDetails(componentsDetails)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private List<ComponentValue> toComponentList(ComponentLogEntry componentLogEntry) {
|
||||
|
||||
return componentLogEntry.getComponentValues()
|
||||
.stream()
|
||||
.map(this::convert)
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
private ComponentValue convert(ComponentLogEntryValue componentValue) {
|
||||
|
||||
return ComponentValue.builder()
|
||||
.valueDescription(componentValue.getValueDescription())
|
||||
.componentRuleId(componentValue.getComponentRuleId())
|
||||
.entityReferences(componentValue.getComponentLogEntityReferences()
|
||||
.stream()
|
||||
.map(this::convertComponentEntityReference)
|
||||
.toList())
|
||||
.originalValue(componentValue.getOriginalValue())
|
||||
.value(componentValue.getValue())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private EntityReference convertComponentEntityReference(ComponentLogEntityReference componentLogEntityReference) {
|
||||
|
||||
return EntityReference.builder()
|
||||
.id(componentLogEntityReference.getId())
|
||||
.entityRuleId(componentLogEntityReference.getEntityRuleId())
|
||||
.type(componentLogEntityReference.getType())
|
||||
.page(componentLogEntityReference.getPage())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@ -119,11 +102,101 @@ public class ComponentControllerV2 implements ComponentResource {
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails) {
|
||||
|
||||
dossierTemplateController.getDossierTemplate(dossierTemplateId);
|
||||
checkApplicationType();
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
var dossierFiles = statusController.getDossierStatus(dossierId);
|
||||
|
||||
if(dossierFiles.size() > documineComponentsFilesLimit) {
|
||||
throw new BadRequestException(String.format("The dossier you requested components for contains %s files this is above the limit of %s files for this endpoint, please use the POST %s", dossierFiles.size(), documineComponentsFilesLimit, FILE_PATH + BULK_COMPONENTS_PATH));
|
||||
}
|
||||
|
||||
return new FileComponentsList(dossierFiles.stream()
|
||||
.map(file -> getComponents(dossierTemplateId, dossierId, file.getFileId(), includeDetails))
|
||||
.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FileComponentsList getComponentsForFiles(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails,
|
||||
@RequestBody BulkComponentsRequest bulkComponentsRequest){
|
||||
|
||||
if(bulkComponentsRequest.getFileIds().size() > documineComponentsFilesLimit) {
|
||||
throw new BadRequestException(String.format("You requested components for %s files this is above the limit of %s files for this endpoint, lower the fileIds in the request", bulkComponentsRequest.getFileIds().size(), documineComponentsFilesLimit));
|
||||
}
|
||||
|
||||
checkApplicationType();
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
dossierController.getDossier(dossierId, false, false);
|
||||
return new FileComponentsList(bulkComponentsRequest.getFileIds().stream()
|
||||
.map(fileId -> getComponents(dossierTemplateId, dossierId, fileId, includeDetails))
|
||||
.toList());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public void addOverride(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@PathVariable(FILE_ID_PARAM) String fileId,
|
||||
@RequestBody Component override) {
|
||||
|
||||
checkApplicationType();
|
||||
accessControlService.verifyUserIsReviewer(dossierId, fileId);
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
componentLogService.overrideComponent(dossierId, fileId, componentMapper.toComponentLogEntry(override));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public ComponentOverrideList getOverrides(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@PathVariable(FILE_ID_PARAM) String fileId) {
|
||||
|
||||
checkApplicationType();
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
FileModel status = fileStatusService.getStatus(fileId);
|
||||
|
||||
var overrides = componentLogService.getComponentLog(dossierId, fileId).getComponentLogEntries()
|
||||
.stream()
|
||||
.filter(ComponentLogEntry::isOverridden)
|
||||
.collect(Collectors.toList());
|
||||
var componentOverrides = componentMapper.toComponents(overrides);
|
||||
|
||||
return ComponentOverrideList.builder()
|
||||
.dossierTemplateId(dossierTemplateId)
|
||||
.dossierId(dossierId)
|
||||
.fileId(fileId)
|
||||
.componentOverrides(status.isSoftOrHardDeleted() ? new ArrayList<>() : componentOverrides)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + GET_RSS + "')")
|
||||
public void revertOverrides(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@PathVariable(FILE_ID_PARAM) String fileId,
|
||||
@RequestBody RevertOverrideRequest revertOverrideRequest) {
|
||||
|
||||
checkApplicationType();
|
||||
accessControlService.verifyUserIsReviewer(dossierId, fileId);
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
componentLogService.revertOverrides(dossierId, fileId, revertOverrideRequest);
|
||||
}
|
||||
|
||||
|
||||
private void checkApplicationType() {
|
||||
|
||||
if (!currentApplicationTypeProvider.isDocuMine()) {
|
||||
throw new NotAllowedException("Components can only be accessed in DocuMine");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,35 +1,67 @@
|
||||
package com.iqser.red.persistence.service.v2.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_DOSSIER_ATTRIBUTES;
|
||||
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_ID_PARAM;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DownloadController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.StatusController;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.CurrentApplicationTypeProvider;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierAttributesManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.PrepareDownloadWithOptionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DownloadFileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierAttribute;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierAttributes;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DocuMineDossierRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatus;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "2. Dossier endpoints", description = "Provides operations related to dossiers")
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class DossierControllerV2 implements DossierResource {
|
||||
|
||||
private final DossierTemplateController dossierTemplateController;
|
||||
private final DossierController dossierController;
|
||||
DossierTemplateController dossierTemplateController;
|
||||
DossierController dossierController;
|
||||
AccessControlService accessControlService;
|
||||
DossierAttributesManagementService dossierAttributesManagementService;
|
||||
AuditPersistenceService auditPersistenceService;
|
||||
DownloadController downloadController;
|
||||
StatusController statusController;
|
||||
DownloadStatusPersistenceService downloadStatusPersistenceService;
|
||||
CurrentApplicationTypeProvider currentApplicationTypeProvider;
|
||||
|
||||
|
||||
public DossierList getDossiers(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@ -71,15 +103,88 @@ public class DossierControllerV2 implements DossierResource {
|
||||
|
||||
|
||||
public void deleteDossier(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier to retrieve.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId) {
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier to retrieve.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestParam(name = DELETE_PERMANENTLY_PARAM, defaultValue = "false", required = false) boolean deletePermanently) {
|
||||
|
||||
dossierTemplateController.getDossierTemplate(dossierTemplateId);
|
||||
|
||||
dossierController.deleteDossier(dossierId);
|
||||
if (deletePermanently) {
|
||||
dossierController.hardDeleteDossiers(Sets.newHashSet(dossierId));
|
||||
} else {
|
||||
dossierController.deleteDossier(dossierId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static DossierRequest mapToDossierRequest(String dossierTemplateId, DocuMineDossierRequest dossier) {
|
||||
@PreAuthorize("hasAuthority('" + WRITE_DOSSIER_ATTRIBUTES + "')")
|
||||
public void setDossierAttributes(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestBody DossierAttributes dossierAttributes) {
|
||||
|
||||
dossierTemplateController.getDossierTemplate(dossierTemplateId);
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyUserIsDossierOwner(dossierId);
|
||||
|
||||
var dossierAttributeList = dossierAttributes.getAttributeIdToValue().entrySet()
|
||||
.stream()
|
||||
.map(entry -> new DossierAttribute(dossierId, entry.getKey(), entry.getValue()))
|
||||
.toList();
|
||||
|
||||
dossierAttributesManagementService.setDossierAttributes(dossierId, dossierAttributeList);
|
||||
auditPersistenceService.insertRecord(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierId)
|
||||
.category(AuditCategory.DOSSIER.name())
|
||||
.message("Changed dossier attributes.")
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
public DownloadStatus prepareDossierDownload(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestBody DownloadRequest downloadRequest) {
|
||||
|
||||
dossierTemplateController.getDossierTemplate(dossierTemplateId);
|
||||
|
||||
var storageId = downloadController.prepareDownload(PrepareDownloadWithOptionRequest.builder()
|
||||
.dossierId(dossierId)
|
||||
.fileIds(statusController.getDossierStatus(dossierId)
|
||||
.stream()
|
||||
.map(FileStatus::getId)
|
||||
.toList())
|
||||
.reportTemplateIds(downloadRequest.getReportTemplateIds())
|
||||
.downloadFileTypes(downloadRequest.getDownloadFileTypes())
|
||||
.redactionPreviewColor(downloadRequest.getRedactionPreviewColor())
|
||||
.includeUnprocessed(false)
|
||||
.build()).getStorageId();
|
||||
|
||||
var status = downloadStatusPersistenceService.getStatus(storageId);
|
||||
|
||||
return DownloadStatus.builder()
|
||||
.id(status.getUuid()) // This is a workaround the real is the storageId.
|
||||
.userId(status.getUserId())
|
||||
.filename(status.getFilename())
|
||||
.mimeType(status.getMimeType())
|
||||
.errorCause(status.getErrorCause())
|
||||
.status(status.getStatus())
|
||||
.creationDate(status.getCreationDate())
|
||||
.lastDownload(status.getLastDownload())
|
||||
.fileSize(status.getFileSize())
|
||||
.dossierId(status.getDossier().getId())
|
||||
.fileIds(status.getFiles()
|
||||
.stream()
|
||||
.map(FileEntity::getId)
|
||||
.toList())
|
||||
.downloadFileTypes(status.getDownloadFileTypes()
|
||||
.stream()
|
||||
.toList())
|
||||
.reportTemplateIds(downloadRequest.getReportTemplateIds())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private DossierRequest mapToDossierRequest(String dossierTemplateId, DocuMineDossierRequest dossier) {
|
||||
|
||||
return DossierRequest.builder()
|
||||
.dossierId(dossier.getId())
|
||||
@ -88,7 +193,7 @@ public class DossierControllerV2 implements DossierResource {
|
||||
.description(dossier.getDescription())
|
||||
.ownerId(dossier.getOwnerId())
|
||||
.memberIds(dossier.getMemberIds())
|
||||
.approverIds(dossier.getMemberIds()) // for DocuMine, the members are always set as approvers
|
||||
.approverIds(currentApplicationTypeProvider.isDocuMine() ? dossier.getMemberIds() : dossier.getApproverIds()) // for DocuMine, the members are always set as approvers
|
||||
.downloadFileTypes(Set.of(DownloadFileType.ORIGINAL))
|
||||
.reportTemplateIds(dossier.getReportTemplateIds())
|
||||
.watermarkId(null)
|
||||
|
||||
@ -1,15 +1,26 @@
|
||||
package com.iqser.red.persistence.service.v2.external.api.impl.controller;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.EXPERIMENTAL;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_REPORT_TEMPLATES;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_DATA_FORMATS;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_DOSSIER_ATTRIBUTES_CONFIG;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_DOSSIER_STATUS;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_FILE_ATTRIBUTES_CONFIG;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_RULES;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_DATA_FORMATS;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_RULES;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@ -23,45 +34,85 @@ import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.FileAttributesController;
|
||||
import com.iqser.red.persistence.service.v2.external.api.impl.mapper.ComponentMappingMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.DateFormatsEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.RuleSetEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ComponentDefinitionEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.model.ComponentMappingDownloadModel;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentDefinitionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentMappingService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DateFormatsValidationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.RulesValidationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DateFormatsPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierAttributeConfigPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ReportTemplatePersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.RulesValidationMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinition;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionAddRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionUpdateRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DateFormatPatternErrorMessage;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummary;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierAttributeDefinition;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierAttributeDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierStatusDefinition;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierStatusDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileAttributeDefinition;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileAttributeDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.RulesValidationMessage;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.RulesValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ReportTemplate;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ReportTemplateList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource;
|
||||
import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import feign.FeignException;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "1. Dossier templates endpoints", description = "Provides operations related to dossier templates")
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
|
||||
private static final String RULES_DOWNLOAD_FILE_NAME_SUFFIX = "-rules.drl";
|
||||
private static final String DATE_FORMAT_FILE_NAME = "date_formats.txt";
|
||||
|
||||
private final DossierTemplateController dossierTemplateController;
|
||||
private final RulesPersistenceService rulesPersistenceService;
|
||||
private final RulesValidationService rulesValidationService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
private final FileAttributesController fileAttributesController;
|
||||
DossierTemplateController dossierTemplateController;
|
||||
RulesPersistenceService rulesPersistenceService;
|
||||
DateFormatsPersistenceService dateFormatsPersistenceService;
|
||||
RulesValidationService rulesValidationService;
|
||||
DateFormatsValidationService dateFormatsValidationService;
|
||||
AuditPersistenceService auditPersistenceService;
|
||||
FileAttributesController fileAttributesController;
|
||||
ComponentMappingService componentMappingService;
|
||||
ComponentMappingMapper componentMappingMapper = ComponentMappingMapper.INSTANCE;
|
||||
DossierTemplatePersistenceService dossierTemplatePersistenceService;
|
||||
DossierStatusPersistenceService dossierStatusPersistenceService;
|
||||
DossierAttributeConfigPersistenceService dossierAttributeConfigPersistenceService;
|
||||
ComponentDefinitionService componentDefinitionService;
|
||||
ReportTemplatePersistenceService reportTemplatePersistenceService;
|
||||
|
||||
|
||||
public List<DossierTemplateModel> getAllDossierTemplates() {
|
||||
@ -76,13 +127,12 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "') and hasAuthority('" + EXPERIMENTAL + "')")
|
||||
public ResponseEntity<RulesValidationResponse> uploadEntityRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun) {
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public ResponseEntity<DroolsValidationResponse> uploadEntityRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun) {
|
||||
|
||||
// Try to get dossier template to return 404 if it does not exist
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
return uploadRules(dossierTemplateId, RuleFileType.ENTITY, file, dryRun);
|
||||
}
|
||||
@ -91,20 +141,18 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
|
||||
public ResponseEntity<?> downloadEntityRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
// Try to get dossier template to return 404 if it does not exist
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
return downloadRules(dossierTemplateId, RuleFileType.ENTITY);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "') and hasAuthority('" + EXPERIMENTAL + "')")
|
||||
public ResponseEntity<RulesValidationResponse> uploadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun) {
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public ResponseEntity<DroolsValidationResponse> uploadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun) {
|
||||
|
||||
// Try to get dossier template to return 404 if it does not exist
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
return uploadRules(dossierTemplateId, RuleFileType.COMPONENT, file, dryRun);
|
||||
}
|
||||
@ -113,18 +161,69 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
|
||||
public ResponseEntity<?> downloadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
// Try to get dossier template to return 404 if it does not exist
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
return downloadRules(dossierTemplateId, RuleFileType.COMPONENT);
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@PreAuthorize("hasAuthority('" + WRITE_DATA_FORMATS + "')")
|
||||
public ResponseEntity<?> uploadDateFormats(String dossierTemplateId, MultipartFile file) {
|
||||
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
if (originalFilename == null || !originalFilename.endsWith(".txt")) {
|
||||
throw new BadRequestException("Only .txt files can be parsed.");
|
||||
}
|
||||
|
||||
String dateFormats = new String(file.getBytes(), StandardCharsets.UTF_8);
|
||||
|
||||
List<DateFormatPatternErrorMessage> dateFormatPatternErrorMessages = dateFormatsValidationService.validateDateFormats(dateFormats);
|
||||
if (!dateFormatPatternErrorMessages.isEmpty()) {
|
||||
return new ResponseEntity<>(dateFormatPatternErrorMessages, HttpStatus.UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
dateFormatsPersistenceService.setDateFormats(dateFormats, dossierTemplateId);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("date formats have been updated")
|
||||
.build());
|
||||
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@PreAuthorize("hasAuthority('" + READ_DATA_FORMATS + "')")
|
||||
public ResponseEntity<?> downloadDateFormats(String dossierTemplateId) {
|
||||
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
Optional<DateFormatsEntity> dateFormatsOptional = dateFormatsPersistenceService.getDateFormats(dossierTemplateId);
|
||||
if (dateFormatsOptional.isEmpty()) {
|
||||
throw new NotFoundException(String.format("No date formats found for dossierTemplateId %s", dossierTemplateId));
|
||||
}
|
||||
var data = dateFormatsOptional.get().getValue().getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
|
||||
httpHeaders.add("Content-Disposition", "attachment" + "; filename*=utf-8''" + StringEncodingUtils.urlEncode(DATE_FORMAT_FILE_NAME));
|
||||
|
||||
InputStream is = new ByteArrayInputStream(data);
|
||||
|
||||
return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_FILE_ATTRIBUTES_CONFIG + "')")
|
||||
public FileAttributeDefinitionList getFileAttributeDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
// Try to get dossier template to return 404 if it does not exist
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
var fileAttributeConfigs = fileAttributesController.getFileAttributesConfiguration(dossierTemplateId);
|
||||
|
||||
@ -148,6 +247,7 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
.filterable(fileAttributeConfig.isFilterable())
|
||||
.displayedInFileList(fileAttributeConfig.isDisplayedInFileList())
|
||||
.build())
|
||||
.includeInCsvExport(fileAttributeConfig.isIncludeInCsvExport())
|
||||
.build())
|
||||
.toList();
|
||||
|
||||
@ -155,28 +255,383 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
|
||||
public ComponentMappingSummary getComponentMappingSummaries(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
List<com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata> summaries = componentMappingService.getMetaDataByDossierTemplateId(
|
||||
dossierTemplateId);
|
||||
List<ComponentMappingMetadataModel> componentMappingMetadataModelList = componentMappingMapper.toModelList(summaries);
|
||||
return new ComponentMappingSummary(dossierTemplateId, componentMappingMetadataModelList);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
private ResponseEntity<RulesValidationResponse> uploadRules(String dossierTemplateId, RuleFileType ruleFileType, MultipartFile file, boolean dryRun) {
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public ComponentMappingMetadataModel uploadMapping(String dossierTemplateId, MultipartFile file, String name, String encoding, String delimiter, String quoteChar) {
|
||||
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
if (Strings.isNullOrEmpty(file.getOriginalFilename()) || !file.getOriginalFilename().endsWith(".csv")) {
|
||||
throw new BadRequestException(format("File name \"%s\" does not end with .csv", file.getOriginalFilename()));
|
||||
}
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
|
||||
String nameToUse = Strings.isNullOrEmpty(name) ? fileName.replaceAll(".csv$", "") : name;
|
||||
|
||||
if (Strings.isNullOrEmpty(nameToUse)) {
|
||||
throw new BadRequestException(format("The provided file name \"%s\" is not valid!", nameToUse));
|
||||
}
|
||||
|
||||
char cleanDelimiter = getDelimiter(delimiter);
|
||||
char cleanQuoteChar = getQuoteChar(quoteChar);
|
||||
|
||||
Path mappingFile = saveToFile(file);
|
||||
|
||||
try {
|
||||
|
||||
ComponentMappingMetadata metaData = componentMappingService.create(dossierTemplateId,
|
||||
nameToUse,
|
||||
fileName,
|
||||
cleanDelimiter,
|
||||
encoding,
|
||||
mappingFile.toFile(),
|
||||
cleanQuoteChar);
|
||||
|
||||
return componentMappingMapper.toModel(metaData);
|
||||
} finally {
|
||||
Files.deleteIfExists(mappingFile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public ComponentMappingMetadataModel updateMapping(String dossierTemplateId,
|
||||
String componentMappingId,
|
||||
MultipartFile file,
|
||||
String name,
|
||||
String encoding,
|
||||
String delimiter,
|
||||
String quoteChar) {
|
||||
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
String nameToUse = validateFileName(file, name);
|
||||
|
||||
char cleanDelimiter = getDelimiter(delimiter);
|
||||
char cleanQuoteChar = getQuoteChar(quoteChar);
|
||||
|
||||
Path mappingFile = saveToFile(file);
|
||||
|
||||
try {
|
||||
ComponentMappingMetadata resultMetaData = componentMappingService.update(dossierTemplateId,
|
||||
componentMappingId,
|
||||
nameToUse,
|
||||
encoding,
|
||||
cleanDelimiter,
|
||||
mappingFile.toFile(),
|
||||
file.getOriginalFilename(),
|
||||
cleanQuoteChar);
|
||||
|
||||
return componentMappingMapper.toModel(resultMetaData);
|
||||
} finally {
|
||||
Files.deleteIfExists(mappingFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static char getDelimiter(String delimiter) {
|
||||
|
||||
if (Strings.isNullOrEmpty(delimiter)) {
|
||||
throw new BadRequestException("The provided delimiter is not valid! Can't be null or empty.");
|
||||
} else if (delimiter.length() != 1) {
|
||||
throw new BadRequestException(format("The provided delimiter %s is not valid! Only a single character is allowed.", delimiter));
|
||||
}
|
||||
return delimiter.charAt(0);
|
||||
}
|
||||
|
||||
|
||||
private static char getQuoteChar(String quoteChar) {
|
||||
|
||||
if (Strings.isNullOrEmpty(quoteChar)) {
|
||||
throw new BadRequestException("The provided quoteChar is not valid! Can't be null or empty.");
|
||||
} else if (quoteChar.length() != 1) {
|
||||
throw new BadRequestException(format("The provided quoteChar %s is not valid! Only a single character is allowed.", quoteChar));
|
||||
}
|
||||
return quoteChar.charAt(0);
|
||||
}
|
||||
|
||||
|
||||
private static String validateFileName(MultipartFile file, String name) {
|
||||
|
||||
if (Strings.isNullOrEmpty(file.getOriginalFilename()) || !file.getOriginalFilename().endsWith(".csv")) {
|
||||
throw new BadRequestException(format("File name \"%s\" does not end with .csv", file.getOriginalFilename()));
|
||||
}
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
|
||||
String nameToUse = Strings.isNullOrEmpty(name) ? fileName.replaceAll(".csv$", "") : name;
|
||||
|
||||
if (Strings.isNullOrEmpty(nameToUse)) {
|
||||
throw new BadRequestException(format("The provided file name \"%s\" is not valid!", nameToUse));
|
||||
}
|
||||
return nameToUse;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
|
||||
public ResponseEntity<?> downloadMapping(String dossierTemplateId, String componentMappingId) {
|
||||
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
ComponentMappingDownloadModel mappingDownloadModel = componentMappingService.getMappingForDownload(dossierTemplateId, componentMappingId);
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
|
||||
httpHeaders.add("Content-Disposition",
|
||||
"attachment"
|
||||
+ "; filename*="
|
||||
+ mappingDownloadModel.encoding().toLowerCase(Locale.US)
|
||||
+ "''"
|
||||
+ StringEncodingUtils.urlEncode(mappingDownloadModel.fileName()));
|
||||
|
||||
return new ResponseEntity<>(mappingDownloadModel.mappingFileResource(), httpHeaders, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public ResponseEntity<?> deleteMapping(String dossierTemplateId, String componentMappingId) {
|
||||
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
try {
|
||||
componentMappingService.delete(dossierTemplateId, componentMappingId);
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER_STATUS + "')")
|
||||
public DossierStatusDefinitionList getDossierStatusDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
|
||||
return new DossierStatusDefinitionList(dossierStatusPersistenceService.getAllDossierStatusForTemplate(dossierTemplateId)
|
||||
.stream()
|
||||
.map(dossierStatusInfo -> DossierStatusDefinition.builder()
|
||||
.id(dossierStatusInfo.getId())
|
||||
.name(dossierStatusInfo.getName())
|
||||
.description(dossierStatusInfo.getDescription())
|
||||
.rank(dossierStatusInfo.getRank())
|
||||
.color(dossierStatusInfo.getColor())
|
||||
.dossierCount(dossierStatusInfo.getDossierCount() != null ? dossierStatusInfo.getDossierCount() : 0)
|
||||
.build())
|
||||
.toList());
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER_ATTRIBUTES_CONFIG + "')")
|
||||
public DossierAttributeDefinitionList getDossierAttributeDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
|
||||
return new DossierAttributeDefinitionList(dossierAttributeConfigPersistenceService.getDossierAttributes(dossierTemplateId)
|
||||
.stream()
|
||||
.map(config -> DossierAttributeDefinition.builder()
|
||||
.id(config.getId())
|
||||
.name(config.getLabel())
|
||||
.type(config.getType())
|
||||
.reportingPlaceholder(config.getPlaceholder())
|
||||
.displaySettings(DossierAttributeDefinition.DossierDisplaySettings.builder()
|
||||
.editable(config.isEditable())
|
||||
.filterable(config.isFilterable())
|
||||
.displayedInDossierList(config.isDisplayedInDossierList())
|
||||
.build())
|
||||
.build())
|
||||
.toList());
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_REPORT_TEMPLATES + "')")
|
||||
public ReportTemplateList getReportTemplates(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
var templates = reportTemplatePersistenceService.findByDossierTemplateId(dossierTemplateId);
|
||||
return new ReportTemplateList(templates.stream()
|
||||
.map(t -> ReportTemplate.builder()
|
||||
.id(t.getTemplateId())
|
||||
.name(t.getFileName())
|
||||
.createdOn(t.getUploadDate())
|
||||
.multiFile(t.isMultiFileReport())
|
||||
.preSelect(t.isActiveByDefault())
|
||||
.build())
|
||||
.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> createComponents(String dossierTemplateId, List<ComponentDefinitionAddRequest> componentDefinitionAddRequests) {
|
||||
|
||||
if (componentDefinitionAddRequests.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<ComponentDefinition> componentDefinitions = componentDefinitionService.createComponents(dossierTemplateId, componentDefinitionAddRequests);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components added.")
|
||||
.details(Map.of("Number of added components", componentDefinitions.size()))
|
||||
.build());
|
||||
return componentDefinitions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> getComponents(String dossierTemplateId, boolean includeSoftDeleted) {
|
||||
|
||||
return componentDefinitionService.getComponentsByDossierTemplateId(dossierTemplateId, includeSoftDeleted);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ComponentDefinition getComponent(String dossierTemplateId, String componentId) {
|
||||
|
||||
return componentDefinitionService.getComponentByDossierTemplateIdAndComponentId(dossierTemplateId, componentId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> updateComponents(String dossierTemplateId, List<ComponentDefinitionUpdateRequest> componentDefinitionUpdateRequests) {
|
||||
|
||||
if (componentDefinitionUpdateRequests.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<ComponentDefinition> componentDefinitions = componentDefinitionService.updateComponents(dossierTemplateId, componentDefinitionUpdateRequests);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components updated.")
|
||||
.details(Map.of("Number of updated components", componentDefinitions.size()))
|
||||
.build());
|
||||
return componentDefinitions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void deleteComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
List<ComponentDefinitionEntity> components = componentDefinitionService.deleteComponents(dossierTemplateId, componentIds);
|
||||
if (!components.isEmpty()) {
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components deleted.")
|
||||
.details(Map.of("Number of deleted components", components.size()))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> restoreComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
List<ComponentDefinition> components = componentDefinitionService.restoreComponents(dossierTemplateId, componentIds);
|
||||
if (!components.isEmpty()) {
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components restored.")
|
||||
.details(Map.of("Number of restored components", components.size()))
|
||||
.build());
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> reorderComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
List<ComponentDefinition> orderedComponents = componentDefinitionService.reorderComponents(dossierTemplateId, componentIds);
|
||||
if (!orderedComponents.isEmpty()) {
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components reordered.")
|
||||
.details(Map.of("Number of reordered components", orderedComponents.size()))
|
||||
.build());
|
||||
}
|
||||
return orderedComponents;
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
private static Path saveToFile(MultipartFile file) {
|
||||
|
||||
Path mappingFile = Files.createTempFile(file.getName(), ".csv");
|
||||
|
||||
try (var out = new FileOutputStream(mappingFile.toFile())) {
|
||||
out.write(file.getBytes());
|
||||
}
|
||||
return mappingFile;
|
||||
}
|
||||
|
||||
|
||||
private ResponseEntity<?> downloadRules(String dossierTemplateId, RuleFileType ruleFileType) {
|
||||
|
||||
Optional<RuleSetEntity> ruleEntityOptional = rulesPersistenceService.getRules(dossierTemplateId, ruleFileType);
|
||||
if (ruleEntityOptional.isEmpty()) {
|
||||
throw new NotFoundException(String.format("No rule file of type %s found for dossierTemplateId %s", ruleFileType, dossierTemplateId));
|
||||
}
|
||||
var data = ruleEntityOptional.get().getValue().getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
|
||||
httpHeaders.add("Content-Disposition",
|
||||
"attachment" + "; filename*=utf-8''" + StringEncodingUtils.urlEncode(ruleFileType.name().toLowerCase(Locale.ROOT) + RULES_DOWNLOAD_FILE_NAME_SUFFIX));
|
||||
|
||||
InputStream is = new ByteArrayInputStream(data);
|
||||
|
||||
return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
private ResponseEntity<DroolsValidationResponse> uploadRules(String dossierTemplateId, RuleFileType ruleFileType, MultipartFile file, boolean dryRun) {
|
||||
|
||||
var rulesUploadRequest = RulesUploadRequest.builder()
|
||||
.rules(new String(file.getBytes(), StandardCharsets.UTF_8))
|
||||
.dossierTemplateId(dossierTemplateId)
|
||||
.ruleFileType(ruleFileType)
|
||||
.build();
|
||||
try {
|
||||
DroolsSyntaxValidation droolsSyntaxValidation = rulesValidationService.validateRules(rulesUploadRequest.getRuleFileType(), rulesUploadRequest.getRules());
|
||||
if (!droolsSyntaxValidation.isCompiled()) {
|
||||
var rulesSyntaxErrorMessages = droolsSyntaxValidation.getDroolsSyntaxErrorMessages()
|
||||
.stream()
|
||||
.map(errorMessage -> RulesValidationMessage.builder()
|
||||
.line(errorMessage.getLine())
|
||||
.column(errorMessage.getColumn())
|
||||
.message(errorMessage.getMessage())
|
||||
.build())
|
||||
.toList();
|
||||
|
||||
// TODO Add warning and deprecations to response
|
||||
return new ResponseEntity<>(RulesValidationResponse.builder().errors(rulesSyntaxErrorMessages).build(), HttpStatus.UNPROCESSABLE_ENTITY);
|
||||
DroolsValidationResponse rulesValidationResponse = new DroolsValidationResponse();
|
||||
|
||||
try {
|
||||
var droolsValidation = rulesValidationService.validateRules(rulesUploadRequest.getRuleFileType(), rulesUploadRequest.getRules());
|
||||
rulesValidationResponse = RulesValidationMapper.createFromDroolsValidation(droolsValidation);
|
||||
if (!droolsValidation.isCompiled()) {
|
||||
|
||||
return new ResponseEntity<>(rulesValidationResponse, !dryRun ? HttpStatus.UNPROCESSABLE_ENTITY : HttpStatus.OK);
|
||||
}
|
||||
} catch (FeignException e) {
|
||||
if (e.status() == HttpStatus.BAD_REQUEST.value()) {
|
||||
@ -192,29 +647,10 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(rulesUploadRequest.getDossierTemplateId())
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message(String.format("%s rules have been %s", rulesUploadRequest.getRuleFileType(), dryRun ? "validated" : "updated"))
|
||||
.message(format("%s rules have been %s", rulesUploadRequest.getRuleFileType(), dryRun ? "validated" : "updated"))
|
||||
.build());
|
||||
|
||||
// TODO Add warning and deprecations to response
|
||||
return new ResponseEntity<>(RulesValidationResponse.builder().build(), HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
private ResponseEntity<?> downloadRules(String dossierTemplateId, RuleFileType ruleFileType) {
|
||||
|
||||
var ruleEntity = rulesPersistenceService.getRules(dossierTemplateId, ruleFileType);
|
||||
|
||||
var data = ruleEntity.getValue().getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
|
||||
httpHeaders.add("Content-Disposition",
|
||||
"attachment" + "; filename*=utf-8''" + StringEncodingUtils.urlEncode(ruleFileType.name().toLowerCase(Locale.ROOT) + RULES_DOWNLOAD_FILE_NAME_SUFFIX));
|
||||
|
||||
InputStream is = new ByteArrayInputStream(data);
|
||||
|
||||
return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK);
|
||||
return new ResponseEntity<>(rulesValidationResponse, HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,126 @@
|
||||
package com.iqser.red.persistence.service.v2.external.api.impl.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DownloadController;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ReportTemplateEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.users.model.User;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.RemoveDownloadRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatus;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatusList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.resource.DownloadResource;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "5. Downloads", description = "Operations related to download packages.")
|
||||
public class DownloadControllerV2 implements DownloadResource {
|
||||
|
||||
private final DownloadController downloadController;
|
||||
private final DownloadStatusPersistenceService downloadStatusPersistenceService;
|
||||
private final UserService userService;
|
||||
|
||||
|
||||
@Transactional
|
||||
public DownloadStatusList getDownloadStatusList() {
|
||||
|
||||
validateUserRoles(KeycloakSecurity.getUserId());
|
||||
var downloads = downloadStatusPersistenceService.getStatusesByUser(KeycloakSecurity.getUserId());
|
||||
|
||||
return new DownloadStatusList(downloads.stream().map(
|
||||
status ->
|
||||
DownloadStatus.builder()
|
||||
.id(status.getUuid()) // This is a workaround the real id is the storageId.
|
||||
.userId(status.getUserId())
|
||||
.filename(status.getFilename())
|
||||
.mimeType(status.getMimeType())
|
||||
.errorCause(status.getErrorCause())
|
||||
.status(status.getStatus())
|
||||
.creationDate(status.getCreationDate())
|
||||
.lastDownload(status.getLastDownload())
|
||||
.fileSize(status.getFileSize())
|
||||
.dossierId(status.getDossier() != null ? status.getDossier().getId() : null)
|
||||
.fileIds(status.getFiles()
|
||||
.stream()
|
||||
.map(FileEntity::getId)
|
||||
.toList())
|
||||
.downloadFileTypes(status.getDownloadFileTypes()
|
||||
.stream()
|
||||
.toList())
|
||||
.reportTemplateIds(status.getReports().stream().map(ReportTemplateEntity::getTemplateId).toList())
|
||||
.build()).toList()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public DownloadStatus getDownloadStatus(@PathVariable(DOWNLOAD_ID_PARAM) String downloadId) {
|
||||
|
||||
validateUserRoles(KeycloakSecurity.getUserId());
|
||||
var status = downloadStatusPersistenceService.getStatusesByUuid(downloadId);
|
||||
|
||||
return DownloadStatus.builder()
|
||||
.id(status.getUuid()) // This is a workaround the real id is the storageId.
|
||||
.userId(status.getUserId())
|
||||
.filename(status.getFilename())
|
||||
.mimeType(status.getMimeType())
|
||||
.errorCause(status.getErrorCause())
|
||||
.status(status.getStatus())
|
||||
.creationDate(status.getCreationDate())
|
||||
.lastDownload(status.getLastDownload())
|
||||
.fileSize(status.getFileSize())
|
||||
.dossierId(status.getDossier().getId())
|
||||
.fileIds(status.getFiles()
|
||||
.stream()
|
||||
.map(FileEntity::getId)
|
||||
.toList())
|
||||
.downloadFileTypes(status.getDownloadFileTypes()
|
||||
.stream()
|
||||
.toList())
|
||||
.reportTemplateIds(status.getReports().stream().map(ReportTemplateEntity::getTemplateId).toList())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public void deleteDownload(@PathVariable(DOWNLOAD_ID_PARAM) String downloadId) {
|
||||
|
||||
validateUserRoles(KeycloakSecurity.getUserId());
|
||||
var status = downloadStatusPersistenceService.getStatusesByUuid(downloadId);
|
||||
downloadController.deleteDownloadStatus(new RemoveDownloadRequest(List.of(status.getStorageId())));
|
||||
}
|
||||
|
||||
|
||||
public void download(@PathVariable(DOWNLOAD_ID_PARAM) String downloadId) {
|
||||
|
||||
validateUserRoles(KeycloakSecurity.getUserId());
|
||||
var status = downloadStatusPersistenceService.getStatusesByUuid(downloadId);
|
||||
downloadController.downloadFile(status.getStorageId());
|
||||
}
|
||||
|
||||
|
||||
private void validateUserRoles(String userId) {
|
||||
|
||||
Optional<User> userOptional = userService.getUserById(userId);
|
||||
if (userOptional.isPresent()) {
|
||||
if (userOptional.get().getRoles()
|
||||
.stream()
|
||||
.noneMatch(ApplicationRoles.VALID_MEMBER_ROLES::contains)) {
|
||||
throw new NotAllowedException("User doesn't have appropriate roles");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,205 @@
|
||||
package com.iqser.red.persistence.service.v2.external.api.impl.controller;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.multipart.support.MissingServletRequestPartException;
|
||||
|
||||
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
|
||||
import com.iqser.red.commons.spring.ErrorMessage;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
import com.mchange.rmi.NotAuthorizedException;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
@RequiredArgsConstructor
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class ExternalControllerAdviceV2 {
|
||||
|
||||
private final Scheduler scheduler;
|
||||
|
||||
|
||||
@Hidden
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||
@ExceptionHandler(value = NotFoundException.class)
|
||||
public ErrorMessage handleContentNotFoundException(NotFoundException e) {
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/* error handling */
|
||||
|
||||
|
||||
@Hidden
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(value = BadRequestException.class)
|
||||
public ErrorMessage handleBadRequestException(BadRequestException e) {
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@Hidden
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.CONFLICT)
|
||||
@ExceptionHandler(value = {ConflictException.class})
|
||||
protected ErrorMessage handleConflictException(ConflictException e) {
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.FORBIDDEN)
|
||||
@ExceptionHandler({AccessDeniedException.class})
|
||||
public ErrorMessage handleAccessDeniedException(AccessDeniedException e) {
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.UNAUTHORIZED)
|
||||
@ExceptionHandler({NotAuthorizedException.class})
|
||||
public ErrorMessage handleNotAuthorizedException(NotAuthorizedException e) {
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.FORBIDDEN)
|
||||
@ExceptionHandler({NotAllowedException.class})
|
||||
public ErrorMessage handleNotAllowedException(NotAllowedException e) {
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@Hidden
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
@ExceptionHandler({org.springframework.security.acls.model.NotFoundException.class})
|
||||
public ErrorMessage handleACLNotFound(org.springframework.security.acls.model.NotFoundException e) {
|
||||
|
||||
// in case this error occurs on a rest request / force trigger the sync job
|
||||
try {
|
||||
scheduler.triggerJob(new JobKey("SyncUserPermissionsJob"), new JobDataMap(Map.of("tenantId", TenantContext.getTenantId())));
|
||||
} catch (SchedulerException ex) {
|
||||
log.debug("Failed to force trigger SyncUserPermissionsJob", ex);
|
||||
}
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@Hidden
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler({MethodArgumentNotValidException.class})
|
||||
public ErrorMessage handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||
|
||||
var errorList = e.getFieldErrors();
|
||||
String errorListAsString = errorList.stream()
|
||||
.map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage())
|
||||
.collect(Collectors.joining(", "));
|
||||
return new ErrorMessage(OffsetDateTime.now(), String.format("You have empty/wrong formatted parameters: %s", errorListAsString));
|
||||
}
|
||||
|
||||
|
||||
@Hidden
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler({MissingServletRequestPartException.class})
|
||||
public ErrorMessage handleMissingServletRequestPartException(MissingServletRequestPartException e) {
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@Hidden
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler({HttpMessageNotReadableException.class})
|
||||
public ErrorMessage handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
|
||||
|
||||
var cause = e.getCause();
|
||||
if (cause instanceof InvalidFormatException) {
|
||||
InvalidFormatException invalidFormatException = (InvalidFormatException) cause;
|
||||
|
||||
Class<?> targetType = invalidFormatException.getTargetType();
|
||||
if (targetType != null && targetType.isEnum()) {
|
||||
return new ErrorMessage(OffsetDateTime.now(), String.format("Unsupported value for %s", targetType.getSimpleName()));
|
||||
}
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), cause.getMessage());
|
||||
}
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@Hidden
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(value = DataIntegrityViolationException.class)
|
||||
public ErrorMessage handleDataIntegrityViolationException(DataIntegrityViolationException exception) {
|
||||
|
||||
String message = Objects.requireNonNull(exception.getRootCause()).getMessage();
|
||||
if (message.contains("uq_component_definition_technical_name_template")) {
|
||||
message = "A component with the same technical name already exists in the given dossier template.";
|
||||
} else if (message.contains("value too long for type character varying")) {
|
||||
message = "Value is too long. Please use a shorter value.";
|
||||
} else {
|
||||
message = "Database error occurred.";
|
||||
}
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), message);
|
||||
}
|
||||
|
||||
|
||||
@Order(10000)
|
||||
public static class BinderControllerAdvice {
|
||||
|
||||
@InitBinder
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
// This code protects Spring Core from a "Remote Code Execution" attack (dubbed "Spring4Shell").
|
||||
// By applying this mitigation, you prevent the "Class Loader Manipulation" attack vector from firing.
|
||||
// For more details, see this post: https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/
|
||||
String[] denylist = new String[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};
|
||||
dataBinder.setDisallowedFields(denylist);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,9 +7,7 @@ import static com.iqser.red.service.persistence.service.v2.api.external.resource
|
||||
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_ID_PARAM;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -20,15 +18,22 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DownloadController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.FileAttributesController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.FileManagementController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.StatusController;
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.UploadController;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileUploadResult;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.PrepareDownloadWithOptionRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.BulkDownloadRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatus;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileDeleteRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileStatusList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource;
|
||||
@ -48,16 +53,19 @@ public class FileControllerV2 implements FileResource {
|
||||
private final FileStatusManagementService fileStatusManagementService;
|
||||
private final FileAttributesController fileAttributesController;
|
||||
private final DossierTemplateController dossierTemplateController;
|
||||
private final DownloadController downloadController;
|
||||
private final DownloadStatusPersistenceService downloadStatusPersistenceService;
|
||||
|
||||
|
||||
public FileUploadResult upload(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestPart(name = FILE_PARAM) MultipartFile file,
|
||||
@RequestParam(value = KEEP_MANUAL_CHANGES_PARAM, required = false, defaultValue = "false") boolean keepManualChanges) {
|
||||
@RequestParam(value = KEEP_MANUAL_CHANGES_PARAM, required = false, defaultValue = "false") boolean keepManualChanges,
|
||||
@RequestParam(value = DISABLE_AUTOMATIC_ANALYSIS_PARAM, required = false, defaultValue = "false") boolean disableAutomaticAnalysis) {
|
||||
|
||||
dossierTemplateController.getDossierTemplate(dossierTemplateId);
|
||||
|
||||
return uploadController.upload(file, dossierId, keepManualChanges);
|
||||
return uploadController.upload(file, dossierId, keepManualChanges, disableAutomaticAnalysis);
|
||||
}
|
||||
|
||||
|
||||
@ -68,10 +76,11 @@ public class FileControllerV2 implements FileResource {
|
||||
@RequestParam(name = INCLUDE_SOFT_DELETED_PARAM, defaultValue = "false", required = false) boolean includeSoftDeleted) {
|
||||
|
||||
dossierTemplateController.getDossierTemplate(dossierTemplateId);
|
||||
dossierController.getDossier(dossierId, includeArchived, includeSoftDeleted);
|
||||
|
||||
List<FileStatus> fileStatusList = new ArrayList<>();
|
||||
|
||||
if (!includeArchived && dossierController.getDossier(dossierId, includeArchived, includeSoftDeleted).getArchivedTime() != null) {
|
||||
if (!includeArchived && dossierController.getDossier(dossierId, false, includeSoftDeleted).getArchivedTime() != null) {
|
||||
return new FileStatusList(fileStatusList);
|
||||
}
|
||||
|
||||
@ -141,4 +150,60 @@ public class FileControllerV2 implements FileResource {
|
||||
fileAttributesController.setFileAttributes(dossierId, fileId, fileAttributes);
|
||||
}
|
||||
|
||||
|
||||
public DownloadStatus prepareFileDownload(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@PathVariable(FILE_ID_PARAM) String fileId,
|
||||
@RequestBody DownloadRequest downloadRequest) {
|
||||
|
||||
return prepareBulkDownload(dossierTemplateId,
|
||||
dossierId,
|
||||
BulkDownloadRequest.builder()
|
||||
.reportTemplateIds(downloadRequest.getReportTemplateIds())
|
||||
.downloadFileTypes(downloadRequest.getDownloadFileTypes())
|
||||
.redactionPreviewColor(downloadRequest.getRedactionPreviewColor())
|
||||
.fileIds(List.of(fileId))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
public DownloadStatus prepareBulkDownload(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestBody BulkDownloadRequest bulkDownloadRequest) {
|
||||
|
||||
dossierTemplateController.getDossierTemplate(dossierTemplateId);
|
||||
|
||||
var storageId = downloadController.prepareDownload(PrepareDownloadWithOptionRequest.builder()
|
||||
.dossierId(dossierId)
|
||||
.fileIds(bulkDownloadRequest.getFileIds())
|
||||
.reportTemplateIds(bulkDownloadRequest.getReportTemplateIds())
|
||||
.downloadFileTypes(bulkDownloadRequest.getDownloadFileTypes())
|
||||
.redactionPreviewColor(bulkDownloadRequest.getRedactionPreviewColor())
|
||||
.includeUnprocessed(false)
|
||||
.build()).getStorageId();
|
||||
|
||||
var status = downloadStatusPersistenceService.getStatus(storageId);
|
||||
|
||||
return DownloadStatus.builder()
|
||||
.id(status.getUuid()) // This is a workaround the real is the storageId.
|
||||
.userId(status.getUserId())
|
||||
.filename(status.getFilename())
|
||||
.mimeType(status.getMimeType())
|
||||
.errorCause(status.getErrorCause())
|
||||
.status(status.getStatus())
|
||||
.creationDate(status.getCreationDate())
|
||||
.lastDownload(status.getLastDownload())
|
||||
.fileSize(status.getFileSize())
|
||||
.dossierId(status.getDossier().getId())
|
||||
.fileIds(status.getFiles()
|
||||
.stream()
|
||||
.map(FileEntity::getId)
|
||||
.toList())
|
||||
.downloadFileTypes(status.getDownloadFileTypes()
|
||||
.stream()
|
||||
.toList())
|
||||
.reportTemplateIds(bulkDownloadRequest.getReportTemplateIds())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "5. License endpoints", description = "Provides operations related to the license")
|
||||
@Tag(name = "7. License", description = "Operations related to license information and usage metrics.")
|
||||
public class LicenseControllerV2 implements LicenseResource {
|
||||
|
||||
private final LicenseReportController licenseReportController;
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
package com.iqser.red.persistence.service.v2.external.api.impl.mapper;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.Component;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentValue;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents;
|
||||
|
||||
@Mapper
|
||||
public interface ComponentMapper {
|
||||
|
||||
ComponentMapper INSTANCE = Mappers.getMapper(ComponentMapper.class);
|
||||
|
||||
|
||||
@Mapping(target = "entityReferences", source = "componentLogEntityReferences")
|
||||
ComponentValue toComponentValue(ComponentLogEntryValue entry);
|
||||
|
||||
|
||||
@Mapping(target = "componentLogEntityReferences", source = "entityReferences")
|
||||
ComponentLogEntryValue toComponentLogEntry(ComponentValue value);
|
||||
|
||||
|
||||
List<ComponentValue> toComponentValues(List<ComponentLogEntryValue> entries);
|
||||
|
||||
|
||||
List<ComponentLogEntryValue> toComponentLogEntries(List<ComponentValue> values);
|
||||
|
||||
@Mapping(target = "componentValues", source = "values")
|
||||
Component toComponent(ComponentLogEntry entry);
|
||||
|
||||
|
||||
List<Component> toComponents(List<ComponentLogEntry> entries);
|
||||
|
||||
@Mapping(target = "values", source = "componentValues")
|
||||
ComponentLogEntry toComponentLogEntry(Component component);
|
||||
|
||||
|
||||
default FileComponents toFileComponents(ComponentLog componentLog, String dossierTemplateId, String dossierId, String fileId, String fileName, boolean includeDetails) {
|
||||
|
||||
Map<String, List<String>> basicComponent = new LinkedHashMap<>();
|
||||
for (ComponentLogEntry componentLogEntry : componentLog.getComponentLogEntries()) {
|
||||
basicComponent.put(componentLogEntry.getName(),
|
||||
componentLogEntry.getValues()
|
||||
.stream()
|
||||
.map(ComponentLogEntryValue::getValue)
|
||||
.toList());
|
||||
}
|
||||
|
||||
Map<String, Component> componentsDetails = new LinkedHashMap<>();
|
||||
if (includeDetails) {
|
||||
for (ComponentLogEntry entry : componentLog.getComponentLogEntries()) {
|
||||
componentsDetails.put(entry.getName(), toComponent(entry));
|
||||
}
|
||||
}
|
||||
|
||||
return FileComponents.builder()
|
||||
.dossierTemplateId(dossierTemplateId)
|
||||
.dossierId(dossierId)
|
||||
.filename(fileName)
|
||||
.fileId(fileId)
|
||||
.components(basicComponent)
|
||||
.componentDetails(componentsDetails)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.iqser.red.persistence.service.v2.external.api.impl.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel;
|
||||
|
||||
@Mapper
|
||||
public interface ComponentMappingMapper {
|
||||
|
||||
ComponentMappingMapper INSTANCE = Mappers.getMapper(ComponentMappingMapper.class);
|
||||
|
||||
|
||||
ComponentMappingMetadataModel toModel(ComponentMappingMetadata componentMappingMetadata);
|
||||
|
||||
|
||||
List<ComponentMappingMetadataModel> toModelList(List<ComponentMappingMetadata> componentMappingMetadata);
|
||||
|
||||
|
||||
ComponentMappingMetadata toDto(ComponentMappingMetadataModel componentMappingMetadataModel);
|
||||
|
||||
|
||||
List<ComponentMappingMetadata> toDtoList(List<ComponentMappingMetadataModel> componentMappingMetadataModels);
|
||||
|
||||
}
|
||||
@ -20,7 +20,7 @@ dependencies {
|
||||
exclude(group = "com.iqser.red.service", module = "persistence-service-internal-api-v1")
|
||||
exclude(group = "com.iqser.red.service", module = "persistence-service-shared-api-v1")
|
||||
}
|
||||
api("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.4")
|
||||
api("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2")
|
||||
api("com.google.guava:guava:31.1-jre")
|
||||
api("org.springframework.boot:spring-boot-starter-security:3.1.3")
|
||||
api("org.springframework.boot:spring-boot-starter-validation:3.1.3")
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record UpdateEntries(List<String> entriesToAdd, List<String> entriesToDelete) {
|
||||
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentsOverrides;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public interface ComponentLogResource {
|
||||
|
||||
String COMPONENT_LOG_PATH = ExternalApi.BASE_PATH + "/componentLog";
|
||||
|
||||
String OVERRIDE_PATH = "/override";
|
||||
|
||||
String DOSSIER_ID = "dossierId";
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
|
||||
|
||||
String FILE_ID = "fileId";
|
||||
|
||||
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
|
||||
|
||||
|
||||
@GetMapping(value = COMPONENT_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the component log for a fileId", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The component log is not found.")})
|
||||
ComponentLog getComponentLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(name = "includeOverrides", defaultValue = "true") boolean includeOverrides);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = COMPONENT_LOG_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Adds overrides for components", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@GetMapping(value = COMPONENT_LOG_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets overrides for components", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = COMPONENT_LOG_PATH + OVERRIDE_PATH + "/revert" + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Reverts overrides for components", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest);
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -16,11 +17,13 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.model.UpdateEntries;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.UpdateTypeValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dictionary.Dictionary;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dictionary.DictionaryDifferenceResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;
|
||||
|
||||
@ -44,16 +47,21 @@ public interface DictionaryResource {
|
||||
String ENTRY_PATH_VARIABLE = "/{" + ENTRY_PARAMETER_NAME + "}";
|
||||
|
||||
String DOSSIER_TEMPLATE_PARAMETER_NAME = "dossierTemplateId";
|
||||
String DOSSIER_TEMPLATE_PATH_VARIABLE = "/{dossierTemplateId}";
|
||||
String DOSSIER_TEMPLATE_PATH_VARIABLE = "/{" + DOSSIER_TEMPLATE_PARAMETER_NAME + "}";
|
||||
|
||||
String UPLOAD = "/upload";
|
||||
String DOWNLOAD = "/download";
|
||||
String MERGED = "/merged";
|
||||
String DELETE = "/delete";
|
||||
String DIFFERENCE = "/difference";
|
||||
String UPDATE = "/update";
|
||||
|
||||
String UPDATE_FLAG = "/updateFlag";
|
||||
|
||||
String COLOR_REST_PATH = ExternalApi.BASE_PATH + "/color";
|
||||
|
||||
String DOSSIER_ID_PARAMETER_NAME = "dossierId";
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID_PARAMETER_NAME + "}";
|
||||
|
||||
String INCLUDE_DELETED_PARAMETER_NAME = "includeDeleted";
|
||||
|
||||
@ -95,6 +103,17 @@ public interface DictionaryResource {
|
||||
@RequestParam(value = DICTIONARY_ENTRY_TYPE_PARAM, required = false, defaultValue = DEFAULT_DICTIONARY_ENTRY_TYPE) DictionaryEntryType dictionaryEntryType);
|
||||
|
||||
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = DICTIONARY_REST_PATH + UPDATE + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Update dictionary entries with type.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully updated the dictionary entries."), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The dossier or the entry type is not found."), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
void updateEntries(@PathVariable(TYPE_PARAMETER_NAME) String type,
|
||||
@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@RequestBody UpdateEntries updateEntries,
|
||||
@RequestParam(value = DOSSIER_ID_PARAMETER_NAME, required = false) String dossierId,
|
||||
@RequestParam(value = DICTIONARY_ENTRY_TYPE_PARAM, required = false, defaultValue = DEFAULT_DICTIONARY_ENTRY_TYPE) DictionaryEntryType dictionaryEntryType);
|
||||
|
||||
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = TYPE_PATH + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Updates colors, hint and caseInsensitive of an entry type. Only label, colors and description are updatable for system managed entry types", description = "None")
|
||||
@ -196,4 +215,20 @@ public interface DictionaryResource {
|
||||
@GetMapping(value = COLOR_REST_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
Colors getColors(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);
|
||||
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = DICTIONARY_REST_PATH + UPDATE_FLAG + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE + DOSSIER_ID_PATH_VARIABLE)
|
||||
@Operation(summary = "Updates flags regarding to selected type, dossier and dossier template.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully updated the flags of the type."), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entry type is not found.")})
|
||||
void changeFlags(@PathVariable(TYPE_PARAMETER_NAME) String type,
|
||||
@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@PathVariable(DOSSIER_ID_PARAMETER_NAME) String dossierId,
|
||||
@RequestParam(value = "addToDictionaryAction") boolean addToDictionaryAction);
|
||||
|
||||
|
||||
@PostMapping(value = DICTIONARY_REST_PATH + DIFFERENCE + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Returns the difference between the dictionaries of the dossier template and all the dossiers inside the template for a list of given types.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully returned DictionaryDifferenceResponse."), @ApiResponse(responseCode = "400", description = "The request is not valid.")})
|
||||
DictionaryDifferenceResponse getDictionaryDifference(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestBody Set<String> types);
|
||||
|
||||
}
|
||||
@ -2,6 +2,7 @@ package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
@ -17,6 +18,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeResponseV2;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierInformation;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
|
||||
@ -29,10 +31,12 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
public interface DossierResource {
|
||||
|
||||
String DOSSIER_REST_PATH = ExternalApi.BASE_PATH + "/dossier";
|
||||
String BY_ID_PATH = "/by-id";
|
||||
String DOSSIER_TEMPLATE_PATH = "/dossier-template";
|
||||
String DOSSIER_INFO_PATH = "/info";
|
||||
String DELETED_DOSSIERS_PATH = ExternalApi.BASE_PATH + "/deleted-dossiers";
|
||||
String CHANGES_DETAILS_PATH = "/changes/details";
|
||||
String CHANGES_DETAILS_V2_PATH = "/changes/details/v2";
|
||||
String HARD_DELETE_PATH = "/hard-delete";
|
||||
String UNDELETE_PATH = "/restore";
|
||||
|
||||
@ -62,6 +66,12 @@ public interface DossierResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success")})
|
||||
List<DossierChangeEntry> changesSince(@RequestBody JSONPrimitive<OffsetDateTime> since);
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping(value = DOSSIER_REST_PATH + CHANGES_DETAILS_V2_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "See if there are changes to dossiers since param", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success")})
|
||||
DossierChangeResponseV2 changesSinceV2(@RequestBody JSONPrimitive<OffsetDateTime> since);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping(value = DOSSIER_REST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ -95,6 +105,13 @@ public interface DossierResource {
|
||||
List<Dossier> getDossiers(@RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived,
|
||||
@RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted);
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@PostMapping(value = DOSSIER_REST_PATH+BY_ID_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets dossiers by ids.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
JSONPrimitive<Map<String,Dossier>> getDossiersByIds(@RequestBody JSONPrimitive<Set<String>> dossierIds);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
|
||||
@ -95,8 +95,36 @@ public interface DossierTemplateResource {
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = DOSSIER_TEMPLATE_PATH + IMPORT_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Receives an archive to import", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Archive have successfully imported"), @ApiResponse(responseCode = "400", description = "Validation failed during import"), @ApiResponse(responseCode = "404", description = "The dossier template to update does not exist")})
|
||||
@Operation(summary = "Receives an archive to import", description = """
|
||||
Import process stuck in one of the steps:"
|
||||
0 - Reading the archive content
|
||||
|
||||
1 - store information about the dossier template
|
||||
|
||||
2 - store the colors
|
||||
|
||||
3 - store the watermarks
|
||||
|
||||
4 - store the dossier status
|
||||
|
||||
5 - store the dossier attributes
|
||||
|
||||
6 - store the file attributes
|
||||
|
||||
7 - store the report templates
|
||||
|
||||
8 - store the legal basis
|
||||
|
||||
9 - store the file attribute configuration
|
||||
|
||||
10 - store the component definitions
|
||||
|
||||
11 - store the component mappings
|
||||
|
||||
12 - store the types and entities
|
||||
|
||||
13 - store the rules and component rules""")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Archive have successfully imported"), @ApiResponse(responseCode = "400"), @ApiResponse(responseCode = "404", description = "The dossier template to update does not exist")})
|
||||
DossierTemplateModel importDossierTemplate(@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@RequestParam(value = DOSSIER_TEMPLATE_ID, required = false) String dossierTemplateId,
|
||||
@RequestParam(value = "updateExistingDossierTemplate", required = false, defaultValue = "false") boolean updateExistingDossierTemplate);
|
||||
|
||||
@ -6,12 +6,11 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.FilteredEntityLogRequest;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@ -28,6 +27,8 @@ public interface EntityLogResource {
|
||||
|
||||
String DOSSIER_ID = "dossierId";
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
|
||||
String ANALYSIS_NUMBER = "analysisNumber";
|
||||
String ANALYSIS_NUMBER_PATH_VARIABLE = "/{" + ANALYSIS_NUMBER + "}";
|
||||
|
||||
String FALSE = "false";
|
||||
|
||||
@ -37,17 +38,34 @@ public interface EntityLogResource {
|
||||
"Gets the entity log for a given file. The flag includeUnprocessed will merge into the entity log all the unprocessed changes if it's set to true."
|
||||
+ "Default value for the flag is false.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The dossier / file / entity log is not found.")})
|
||||
EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
|
||||
|
||||
@PostMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/filtered", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the entity log for a fileId grater than the specified date", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The dossier / file / entity log is not found.")})
|
||||
EntityLog getFilteredEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
EntityLogResponse getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody FilteredEntityLogRequest filteredEntityLogRequest);
|
||||
@RequestParam(value = "excludedTypes", required = false, defaultValue = "") List<String> excludedTypes,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
|
||||
|
||||
@GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/filtered", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the entity log for a fileId greater than the specified date", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The dossier / file / entity log is not found.")})
|
||||
EntityLogResponse getFilteredEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody FilteredEntityLogRequest filteredEntityLogRequest);
|
||||
|
||||
|
||||
@GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/pages", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the entity log for a fileId with all entities found on the given page numbers", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The dossier / file / entity log is not found.")})
|
||||
EntityLogResponse getEntityLogWithEntriesOnPages(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "pageNumbers", defaultValue = "") List<Integer> pageNumbers);
|
||||
|
||||
|
||||
@GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + ANALYSIS_NUMBER_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the entity log for a fileId with all entities being analysed in or after iteration with given number", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The dossier / file / entity log is not found.")})
|
||||
EntityLogResponse getEntityLogDeltaUpdate(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@PathVariable(ANALYSIS_NUMBER) Integer analysisNumber,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
|
||||
}
|
||||
|
||||
@ -44,7 +44,11 @@ public interface FileAttributesResource {
|
||||
String FILE_ID = "fileId";
|
||||
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
|
||||
|
||||
Set<String> encodingList = Sets.newHashSet("ISO", "ASCII", "UTF-8");
|
||||
String UTF_ENCODING = "UTF-8";
|
||||
String ASCII_ENCODING = "ASCII";
|
||||
String ISO_ENCODING = "ISO-8859-1";
|
||||
|
||||
Set<String> encodingList = Sets.newHashSet(ISO_ENCODING, ASCII_ENCODING, UTF_ENCODING);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ -72,7 +76,7 @@ public interface FileAttributesResource {
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Delete a specific file attribute.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "NO_CONTENT")})
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "NO_CONTENT")})
|
||||
|
||||
@DeleteMapping(value = FILE_ATTRIBUTES_PATH + CONFIG_PATH + FILE_ATTRIBUTE_PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + FILE_ATTRIBUTE_ID_PATH_VARIABLE)
|
||||
void deleteFileAttribute(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @PathVariable(FILE_ATTRIBUTE_ID) String fileAttributeId);
|
||||
@ -81,7 +85,7 @@ public interface FileAttributesResource {
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Bulk delete file attributes.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "NO_CONTENT")})
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "NO_CONTENT")})
|
||||
|
||||
@PostMapping(value = FILE_ATTRIBUTES_PATH + CONFIG_PATH + FILE_ATTRIBUTE_PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + "/delete")
|
||||
void deleteFileAttributes(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @RequestBody List<String> fileAttributeIds);
|
||||
@ -96,7 +100,7 @@ public interface FileAttributesResource {
|
||||
|
||||
|
||||
@Operation(summary = "Set file attributes to an existing file", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK")})
|
||||
|
||||
@PostMapping(value = FILE_ATTRIBUTES_PATH + SET_PATH + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
void setFileAttributes(@PathVariable(DOSSIER_ID_PARAM) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody FileAttributes fileAttributes);
|
||||
|
||||
@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.highlights.Highlights;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.highlights.TextHighlights;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AnnotationIds;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@ -36,7 +36,7 @@ public interface HighlightsResource {
|
||||
@Operation(summary = "Gets available highlights for the file", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
@GetMapping(value = DOSSIERS_PATH + DOSSIER_ID_PATH_VARIABLE + FILES_PATH + FILE_ID_PATH_VARIABLE + HIGHLIGHTS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
Highlights getHighlights(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
|
||||
TextHighlights getHighlights(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.image.ImageSimilaritySearchRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.image.ImageSimilaritySearchResponse;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
public interface ImageSimilaritySearchResource {
|
||||
|
||||
String IMAGE_SIMILARITY_SEARCH_PATH = ExternalApi.BASE_PATH + "/imageSimilaritySearch";
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@Operation(summary = "Gets similiar images to given image", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "400", description = "Bad request: missing parameter")})
|
||||
@PostMapping(value = IMAGE_SIMILARITY_SEARCH_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
ResponseEntity<ImageSimilaritySearchResponse> getSimilarImages(@RequestBody ImageSimilaritySearchRequest imageSimilaritySearchRequest);
|
||||
|
||||
}
|
||||
@ -28,15 +28,15 @@ public interface LegalBasisMappingResource {
|
||||
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = LEGAL_BASIS_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + DELETE_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "delete some legal basis by their names.", description = "None")
|
||||
@Operation(summary = "delete some legal basis by their technical names.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK")})
|
||||
void deleteLegalBasis(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestBody List<String> legalBasisNames);
|
||||
void deleteLegalBasis(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestBody List<String> legalBasisTechnicalNames);
|
||||
|
||||
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PutMapping(value = LEGAL_BASIS_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Add or update one legalBasis.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK")})
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "400", description = "Missing required parameter")})
|
||||
void addOrUpdateLegalBasis(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestBody LegalBasis legalBasis);
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ public interface LegalBasisMappingResource {
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@GetMapping(value = LEGAL_BASIS_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Set the mapping between legal basis and redaction reason.", description = "None")
|
||||
@Operation(summary = "Get all legal basis mapping in dossier template.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<LegalBasis> getLegalBasisMapping(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
@ -15,13 +14,16 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationComments;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactionResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionBulkLocalRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationBulkLocalRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionBulkLocalRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel;
|
||||
|
||||
@ -56,7 +58,8 @@ public interface ManualRedactionResource {
|
||||
void undo(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<String> annotationIds,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
@RequestParam(value = "includeOnlyUnprocessed", required = false, defaultValue = FALSE) boolean includeOnlyUnprocessed,
|
||||
@RequestParam(value = "includeOnlyLocal", required = false, defaultValue = FALSE) boolean includeOnlyLocal);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ -90,22 +93,45 @@ public interface ManualRedactionResource {
|
||||
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Adds a manual redaction", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
List<ManualAddResponse> addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
ManualRedactionResponse addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<AddRedactionRequestModel> addRedactionRequest);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = MANUAL_REDACTION_REST_PATH
|
||||
+ "/bulk-local/add"
|
||||
+ DOSSIER_ID_PATH_PARAM
|
||||
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Adds a bulk of local redactions", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
ManualRedactionResponse addRedactionBulkLocal(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody AddRedactionBulkLocalRequestModel addRedactionRequest);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = MANUAL_REDACTION_REST_PATH
|
||||
+ "/bulk-local/remove"
|
||||
+ DOSSIER_ID_PATH_PARAM
|
||||
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Removes a bulk of local redactions", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
ManualRedactionResponse removeRedactionBulkLocal(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody RemoveRedactionBulkLocalRequestModel removeRedactionRequest);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = MANUAL_REDACTION_REST_PATH
|
||||
+ "/bulk/redaction/remove"
|
||||
+ DOSSIER_ID_PATH_PARAM
|
||||
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Removes the redactions list", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
List<ManualAddResponse> removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
ManualRedactionResponse removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<RemoveRedactionRequestModel> removeRedactionRequests,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
@RequestBody Set<RemoveRedactionRequestModel> removeRedactionRequests);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ -115,11 +141,12 @@ public interface ManualRedactionResource {
|
||||
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Forces the redactions list", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
List<ManualAddResponse> forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
ManualRedactionResponse forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ForceRedactionRequestModel> forceRedactionRequests);
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = MANUAL_REDACTION_REST_PATH
|
||||
+ "/bulk/redaction/legalBasisChange"
|
||||
@ -127,7 +154,7 @@ public interface ManualRedactionResource {
|
||||
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Changes the legal basis reasons list", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
List<ManualAddResponse> legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
ManualRedactionResponse legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<LegalBasisChangeRequestModel> legalBasisChangeRequests);
|
||||
|
||||
@ -138,11 +165,22 @@ public interface ManualRedactionResource {
|
||||
+ DOSSIER_ID_PATH_PARAM
|
||||
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Recategorizes the list of redaction log entries", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
List<ManualAddResponse> recategorizeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
ManualRedactionResponse recategorizeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<RecategorizationRequestModel> recategorizationRequests,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
@RequestBody Set<RecategorizationRequestModel> recategorizationRequests);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = MANUAL_REDACTION_REST_PATH
|
||||
+ "/bulk-local/recategorize"
|
||||
+ DOSSIER_ID_PATH_PARAM
|
||||
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Recategorizes the list of redaction log entries", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
ManualRedactionResponse recategorizeBulkLocal(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody RecategorizationBulkLocalRequestModel recategorizationRequest);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ -152,10 +190,9 @@ public interface ManualRedactionResource {
|
||||
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Resizes the redactions list", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
List<ManualAddResponse> resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
ManualRedactionResponse resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ResizeRedactionRequestModel> resizeRedactionRequests,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
@RequestBody Set<ResizeRedactionRequestModel> resizeRedactionRequests);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.saas.migration.MigrationStatusResponse;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
public interface MigrationStatusResource {
|
||||
|
||||
String MIGRATION_STATUS_REST_PATH = ExternalApi.BASE_PATH + "/migration-status";
|
||||
String START_MIGRATION_REST_PATH = ExternalApi.BASE_PATH + "/start_migration";
|
||||
String REVERT_MIGRATION_REST_PATH = ExternalApi.BASE_PATH + "/revert_migration";
|
||||
String RETRY_MIGRATION_REST_PATH = ExternalApi.BASE_PATH + "/retry_migration";
|
||||
|
||||
String FILE_ID = "fileId";
|
||||
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
|
||||
|
||||
String DOSSIER_ID = "dossierId";
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping(value = MIGRATION_STATUS_REST_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Show the status of the migration", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success.")})
|
||||
MigrationStatusResponse migrationStatus();
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping(value = START_MIGRATION_REST_PATH + FILE_ID_PATH_VARIABLE + DOSSIER_ID_PATH_VARIABLE)
|
||||
@Operation(summary = "Start SAAS migration for specific file", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success.")})
|
||||
ResponseEntity<?> startMigrationForFile(@RequestParam(value = DOSSIER_ID) String dossierId, @RequestParam(value = FILE_ID) String fileId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping(value = REVERT_MIGRATION_REST_PATH + FILE_ID_PATH_VARIABLE + DOSSIER_ID_PATH_VARIABLE)
|
||||
@Operation(summary = "Start SAAS migration for specific file", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success.")})
|
||||
ResponseEntity<?> revertMigrationForFile(@RequestParam(value = DOSSIER_ID) String dossierId, @RequestParam(value = FILE_ID) String fileId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping(value = RETRY_MIGRATION_REST_PATH)
|
||||
@Operation(summary = "Restart SAAS migration for all files in error state", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success.")})
|
||||
ResponseEntity<?> requeueErrorFiles();
|
||||
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentsOverrides;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSResponse;
|
||||
import com.iqser.red.service.redaction.report.v1.api.model.rss.DetailedRSSResponse;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public interface RSSResource {
|
||||
|
||||
String RSS_PATH = ExternalApi.BASE_PATH + "/rss";
|
||||
String OVERRIDE_PATH = "/override";
|
||||
|
||||
String DOSSIER_ID = "dossierId";
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
|
||||
|
||||
String FILE_ID = "fileId";
|
||||
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@GetMapping(value = RSS_PATH + DOSSIER_ID_PATH_VARIABLE, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
|
||||
@Operation(summary = "Returns the RSS response for a dossier", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
RSSResponse getRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId);
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@GetMapping(value = RSS_PATH + "/detailed" + DOSSIER_ID_PATH_VARIABLE, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
|
||||
@Operation(summary = "Returns the RSS response with more details for a dossier", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
DetailedRSSResponse getDetailedRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId);
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = RSS_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Adds overrides for RSS components", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides);
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@GetMapping(value = RSS_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets overrides for RSS components", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = RSS_PATH + OVERRIDE_PATH + "/revert" + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Reverts overrides for RSS components", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest);
|
||||
|
||||
}
|
||||
@ -38,6 +38,7 @@ public interface ReanalysisResource {
|
||||
|
||||
String EXCLUDED_STATUS_PARAM = "excluded";
|
||||
String FORCE_PARAM = "force";
|
||||
String ALL_PAGES = "allPages";
|
||||
|
||||
|
||||
@PostMapping(value = REANALYSIS_REST_PATH + DOSSIER_ID_PATH_VARIABLE)
|
||||
@ -73,7 +74,8 @@ public interface ReanalysisResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "409", description = "Conflict"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden"), @ApiResponse(responseCode = "400", description = "Cannot OCR approved file")})
|
||||
void ocrFile(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = FORCE_PARAM, required = false, defaultValue = FALSE) boolean force);
|
||||
@RequestParam(value = FORCE_PARAM, required = false, defaultValue = FALSE) boolean force,
|
||||
@RequestParam(value = ALL_PAGES, required = false, defaultValue = FALSE) boolean allPages);
|
||||
|
||||
|
||||
@Operation(summary = "Ocr and reanalyze multiple files for a dossier", description = "None")
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.FilteredRedactionLogRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public interface RedactionLogResource {
|
||||
|
||||
String REDACTION_LOG_PATH = ExternalApi.BASE_PATH + "/redactionLog";
|
||||
String SECTION_GRID_PATH = ExternalApi.BASE_PATH + "/sectionGrid";
|
||||
String SECTION_TEXT_PATH = ExternalApi.BASE_PATH + "/sectionText";
|
||||
|
||||
String FILE_ID = "fileId";
|
||||
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
|
||||
|
||||
String DOSSIER_ID = "dossierId";
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@GetMapping(value = REDACTION_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the redaction log for a fileId", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The redaction log is not found.")})
|
||||
RedactionLog getRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
|
||||
@RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions,
|
||||
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives);
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@GetMapping(value = SECTION_GRID_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the section grid for a fileId", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The section grid is not found.")})
|
||||
SectionGrid getSectionGrid(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@GetMapping(value = SECTION_TEXT_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
|
||||
@Operation(summary = "Gets the text blocks of a document for a fileId", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The section text is not found.")})
|
||||
ResponseEntity<?> getSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
|
||||
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@PostMapping(value = REDACTION_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/filtered", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the redaction log for a fileId grater than the specified date", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The redaction log is not found.")})
|
||||
RedactionLog getFilteredRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody FilteredRedactionLogRequest filteredRedactionLogRequest);
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
@ -14,7 +15,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsSyntaxValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequestModel;
|
||||
|
||||
@ -28,6 +29,7 @@ public interface RulesResource {
|
||||
String RULES_PATH = ExternalApi.BASE_PATH + "/rules";
|
||||
String UPLOAD_PATH = "/upload";
|
||||
String DOWNLOAD_PATH = "/download";
|
||||
String RESET_PATH = "/reset";
|
||||
|
||||
String DOSSIER_TEMPLATE_PARAMETER_NAME = "dossierTemplateId";
|
||||
String DOSSIER_TEMPLATE_PATH_VARIABLE = "/{dossierTemplateId}";
|
||||
@ -46,8 +48,8 @@ public interface RulesResource {
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = RULES_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Takes object containing string or rules as argument, which will be used by the redaction service.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful or rules validation done."), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified.")})
|
||||
ResponseEntity<DroolsSyntaxValidationResponse> upload(@RequestBody RulesUploadRequestModel rules);
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful or rules validation done."), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified."), @ApiResponse(responseCode = "422", description = "Uploaded rules could not be compiled.")})
|
||||
ResponseEntity<DroolsValidationResponse> upload(@RequestBody RulesUploadRequestModel rules);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ -74,20 +76,20 @@ public interface RulesResource {
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = RULES_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + UPLOAD_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
@Operation(summary = "Takes object containing string or rules as argument, which will be used by the redaction service.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful or rules validation done."), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified.")})
|
||||
ResponseEntity<DroolsSyntaxValidationResponse> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@RequestParam(value = DRY_RUN_PARAMETER) boolean dryRun,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file);
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful or rules validation done."), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified."), @ApiResponse(responseCode = "422", description = "Uploaded rules could not be compiled.")})
|
||||
ResponseEntity<DroolsValidationResponse> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@RequestParam(value = DRY_RUN_PARAMETER) boolean dryRun,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = RULES_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + RULE_FILE_TYPE_PATH_VARIABLE + UPLOAD_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
@Operation(summary = "Takes object containing string or rules as argument, which will be used by the redaction service.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful or rules validation done"), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified.")})
|
||||
ResponseEntity<DroolsSyntaxValidationResponse> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType,
|
||||
@RequestParam(value = DRY_RUN_PARAMETER) boolean dryRun,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file);
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful or rules validation done"), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified."), @ApiResponse(responseCode = "422", description = "Uploaded rules could not be compiled.")})
|
||||
ResponseEntity<DroolsValidationResponse> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType,
|
||||
@RequestParam(value = DRY_RUN_PARAMETER) boolean dryRun,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ -105,4 +107,10 @@ public interface RulesResource {
|
||||
@GetMapping(value = RULES_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + RULE_FILE_TYPE_PATH_VARIABLE + DOWNLOAD_PATH)
|
||||
ResponseEntity<?> downloadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType);
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@Operation(summary = "Resets the timeout detected flag in a Rule file.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "No content")})
|
||||
@PutMapping(value = RULES_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + RULE_FILE_TYPE_PATH_VARIABLE + RESET_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
void unlockRules(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType);
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -16,6 +17,8 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
@ -24,6 +27,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
public interface StatusResource {
|
||||
|
||||
String STATUS_REST_PATH = ExternalApi.BASE_PATH + "/status";
|
||||
String BY_ID_PATH = "/by-id";
|
||||
String CHANGES_SINCE_PATH = "/changes";
|
||||
String BULK_REST_PATH = "/bulk";
|
||||
String ASSIGNEE_REST_PATH = "/set-assignee";
|
||||
@ -35,6 +39,7 @@ public interface StatusResource {
|
||||
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
|
||||
|
||||
String ASSIGNEE_ID_REQUEST_PARAM = "assigneeId";
|
||||
String FORCE_REQUEST_PARAM = "force";
|
||||
|
||||
String DELETED_PATH = "/softdeleted";
|
||||
|
||||
@ -54,6 +59,14 @@ public interface StatusResource {
|
||||
Map<String, List<FileStatus>> getDossierStatus(@RequestBody List<String> dossierIds);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@PostMapping(value = STATUS_REST_PATH + BY_ID_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the status for files by dossierId and fileIds.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
JSONPrimitive<Map<String, List<FileStatus>>> getFilesByIds(@RequestBody JSONPrimitive<Map<String, Set<String>>> filesByDossier);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@PostMapping(value = STATUS_REST_PATH + DELETED_PATH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ -105,11 +118,13 @@ public interface StatusResource {
|
||||
@RequestParam(value = ASSIGNEE_ID_REQUEST_PARAM, required = false) String assigneeId);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = STATUS_REST_PATH + "/approved" + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
|
||||
@Operation(summary = "Sets the status APPROVED for a file.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
void setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
ApproveResponse setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@ -139,11 +154,13 @@ public interface StatusResource {
|
||||
@RequestParam(value = ASSIGNEE_ID_REQUEST_PARAM, required = false) String assigneeId);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = STATUS_REST_PATH + "/approved" + DOSSIER_ID_PATH_VARIABLE + BULK_REST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Sets the status APPROVED for a list of files.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
void setStatusApprovedForList(@PathVariable(DOSSIER_ID) String dossierId, @RequestBody List<String> fileIds);
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
List<ApproveResponse> setStatusApprovedForList(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@RequestBody List<String> fileIds,
|
||||
@RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
|
||||
@ -0,0 +1,178 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DownloadResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileExchangeExportRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatusFilter;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.ImportResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.ReanalysisSettings;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.ReanalyzeFilesResponse;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
public interface SupportResource {
|
||||
|
||||
String REANALYSIS_REST_PATH = ExternalApi.BASE_PATH + "/reanalyze";
|
||||
String ERROR_REANALYSIS_REST_PATH = REANALYSIS_REST_PATH + "/error";
|
||||
|
||||
String STATUS_REST_PATH = ExternalApi.BASE_PATH + "/status/filter";
|
||||
String FILE_EXCHANGE_REST_PATH = ExternalApi.BASE_PATH + "/file-exchange";
|
||||
String DATASET_EXCHANGE = ExternalApi.BASE_PATH + "/dataset-exchange";
|
||||
|
||||
String BULK_REST_PATH = "/bulk";
|
||||
|
||||
String DOSSIER_TEMPLATE_ID = "dossierTemplateId";
|
||||
String DOSSIER_ID = "dossierId";
|
||||
String FILE_ID = "fileId";
|
||||
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
|
||||
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
|
||||
String DOSSIER_TEMPLATE_DOSSIER_TEMPLATE_ID_PATH_VARIABLE = "/dossierTemplateId/{" + DOSSIER_TEMPLATE_ID + "}";
|
||||
String DOSSIER_TEMPLATE_ID_PATH_VARIABLE = "/{" + DOSSIER_TEMPLATE_ID + "}";
|
||||
String DOSSIER_DOSSIER_ID_PATH_VARIABLE = "/dossierId/{" + DOSSIER_ID + "}";
|
||||
|
||||
String FALSE = "false";
|
||||
|
||||
String FULL_REANALYSIS_PARAM = "fullReanalysis";
|
||||
String RUN_OCR_PARAM = "runOcr";
|
||||
String EXPORT = "/export";
|
||||
String IMPORT = "/import";
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = REANALYSIS_REST_PATH + DOSSIER_TEMPLATE_DOSSIER_TEMPLATE_ID_PATH_VARIABLE)
|
||||
@Operation(summary = "Reanalyze all files in dossier template", description = """
|
||||
## Reanalyze Files Endpoint
|
||||
|
||||
Use this endpoint to reanalyze all files in a specified Dossier Template. The reanalysis process can be tailored using various filtering options provided in the request body.
|
||||
|
||||
### Parameters
|
||||
|
||||
- **DossierTemplateId**: Specifies the Dossier Template whose files need to be reanalyzed.
|
||||
|
||||
### Request Body Configuration Options
|
||||
|
||||
- **dossierIds**: List of dossier IDs to filter. If empty, all dossiers are selected for reanalysis.
|
||||
- **fileIds**: List of file IDs to filter. If empty, all files are selected for reanalysis.
|
||||
- **repeatStructureAnalysis**: Boolean. If true, layout parsing and named entity recognition will be repeated.
|
||||
- **fileStatusFilter**: Use this to create a filter for files to reanalyze. Matches any file if set to null.
|
||||
""")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
ReanalyzeFilesResponse reanalyzeFiles(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @RequestBody ReanalysisSettings reanalysisSettings);
|
||||
|
||||
|
||||
@PostMapping(value = ERROR_REANALYSIS_REST_PATH)
|
||||
@Operation(summary = "Reanalyze all files in error state.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
void reanalyzeAllRelevantErrorFiles(@RequestParam(value = FULL_REANALYSIS_PARAM, required = false, defaultValue = FALSE) boolean repeatStructureAnalysis,
|
||||
@RequestParam(value = RUN_OCR_PARAM, required = false, defaultValue = FALSE) boolean runOcr);
|
||||
|
||||
|
||||
@PostMapping(value = ERROR_REANALYSIS_REST_PATH + DOSSIER_ID_PATH_VARIABLE + BULK_REST_PATH)
|
||||
@Operation(summary = "Reanalyze multiple files in error state for a dossier.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
void reanalyzeErrorFilesBulkForDossier(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@RequestBody List<String> fileIds,
|
||||
@RequestParam(value = FULL_REANALYSIS_PARAM, required = false, defaultValue = FALSE) boolean repeatStructureAnalysis,
|
||||
@RequestParam(value = RUN_OCR_PARAM, required = false, defaultValue = FALSE) boolean runOcr);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@PostMapping(value = STATUS_REST_PATH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Get the filtered status for all files in the workspace.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<FileStatus> getFileStatus(@RequestBody FileStatusFilter fileStatusFilter);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@PostMapping(value = STATUS_REST_PATH
|
||||
+ DOSSIER_TEMPLATE_DOSSIER_TEMPLATE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Get the filtered status for all files in a dossier template.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<FileStatus> getFileStatusForDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @RequestBody FileStatusFilter fileStatusFilter);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@PostMapping(value = STATUS_REST_PATH + DOSSIER_DOSSIER_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Get the filtered status for all files in a dossier.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<FileStatus> exportFiles(@PathVariable(DOSSIER_ID) String dossierId, @RequestBody FileStatusFilter fileStatusFilter);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@PostMapping(value = FILE_EXCHANGE_REST_PATH
|
||||
+ EXPORT
|
||||
+ DOSSIER_TEMPLATE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Exports all dossiers and files from a given Dossier Template.", description = """
|
||||
## Export Files Endpoint
|
||||
|
||||
Use this endpoint to export a full Dossier Template, including all configurations, dossiers, and files.
|
||||
The endpoint returns a String storageId, which is used to query the DownloadController for the export zip archive's status and to download the archive.
|
||||
|
||||
### Parameters
|
||||
|
||||
- **DossierTemplateId**: Specifies the Dossier Template to be exported.
|
||||
|
||||
### Request Body Configuration Options
|
||||
|
||||
- **dossierIds**: List of dossier IDs to filter. If empty, all dossiers are selected.
|
||||
- **fileIds**: List of file IDs to filter. If empty, all files are selected.
|
||||
- **excludeLayoutFiles**: Boolean. If true, excludes DOCUMENT_STRUCTURE/_PAGES/_TEXT/_POSITIONS, SIMPLIFIED_TEXT, and NER_ENTITIES files.
|
||||
- **excludeManualRedactions**: Boolean. If true, excludes MANUAL_REDACTIONS files.
|
||||
- **excludeAnalysisLogs**: Boolean. If true, excludes ENTITY_LOG and COMPONENT_LOG (with overrides) files.
|
||||
- **excludeFileAttributes**: Boolean. If true, excludes file attributes.
|
||||
- **originFileOnly**: Boolean. If true, exports only the origin file, ignoring untouched and viewer documents.""")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
DownloadResponse exportFiles(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @RequestBody FileExchangeExportRequest exportRequest);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@PostMapping(value = DATASET_EXCHANGE + EXPORT + DOSSIER_TEMPLATE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Exports all dossiers and files from a given Dossier Template.", description = """
|
||||
## Export Preview Files Endpoint
|
||||
|
||||
Use this endpoint to export all files of a DossierTemplate as a Preview file containing all applied annotations as redaction annotations with additional data
|
||||
The endpoint returns a String storageId, which is used to query the DownloadController for the export zip archive's status and to download the archive.
|
||||
""")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
DownloadResponse exportDataset(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = FILE_EXCHANGE_REST_PATH + IMPORT, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Imports a file exchange export zip.", description = "Use this endpoint to import a full export of a given Dossier Template including all its configurations, dossiers, and files. Returns the resulting dossierTemplateId.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
ImportResponse importFiles(@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = DATASET_EXCHANGE + IMPORT, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Imports a file exchange export zip.", description = "Use this endpoint to import a full export of a given Dossier Template including all its configurations, dossiers, and files. Returns the resulting dossierTemplateId.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
ImportResponse importDataset(@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file);
|
||||
|
||||
}
|
||||
@ -15,6 +15,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileUploadResult;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
@ -27,6 +28,7 @@ public interface UploadResource {
|
||||
String IMPORT_REDACTIONS_PATH = ExternalApi.BASE_PATH + "/import-redactions";
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
|
||||
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
|
||||
String DISABLE_AUTOMATIC_ANALYSIS_PARAM = "disableAutomaticAnalysis";
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ -37,7 +39,8 @@ public interface UploadResource {
|
||||
+ "uploaded file."), @ApiResponse(responseCode = "404", description = "Dossier not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
FileUploadResult upload(@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@RequestParam(value = "keepManualRedactions", required = false, defaultValue = "false") boolean keepManualRedactions);
|
||||
@RequestParam(value = "keepManualRedactions", required = false, defaultValue = "false") boolean keepManualRedactions,
|
||||
@Parameter(name = DISABLE_AUTOMATIC_ANALYSIS_PARAM, description = "Disables automatic analysis for the uploaded file, imports only imported redactions") @RequestParam(value = DISABLE_AUTOMATIC_ANALYSIS_PARAM, required = false, defaultValue = "false") boolean disableAutomaticAnalysis);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.UserStats;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "429", description = "Too many requests.")})
|
||||
public interface UserStatsResource {
|
||||
|
||||
String USER_ID_PARAM = "userId";
|
||||
|
||||
String USER_ID_PATH_VARIABLE = "/{" + USER_ID_PARAM + "}";
|
||||
|
||||
String STATS_PATH = "/user-stats";
|
||||
|
||||
String PATH = ExternalApi.BASE_PATH + STATS_PATH;
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@GetMapping(value = PATH + USER_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets user stats for user specified by id.", description = "")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
ResponseEntity<UserStats> getUserStats(@Parameter(name = USER_ID_PARAM, description = "The unique identifier of the user whose statistics we want to retrieve.", required = true) @PathVariable(USER_ID_PARAM) String userId);
|
||||
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id("com.iqser.red.service.java-conventions")
|
||||
id("io.freefair.lombok") version "8.4"
|
||||
id("io.freefair.lombok") version "8.6"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -22,7 +22,7 @@ dependencies {
|
||||
exclude(group = "com.iqser.red.service", module = "persistence-service-internal-api-v1")
|
||||
exclude(group = "com.iqser.red.service", module = "persistence-service-shared-api-v1")
|
||||
}
|
||||
api("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.16.0")
|
||||
api("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2")
|
||||
api("com.google.guava:guava:31.1-jre")
|
||||
api("org.springframework.boot:spring-boot-starter-security:3.1.3")
|
||||
api("org.springframework.boot:spring-boot-starter-validation:3.1.3")
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BulkComponentsRequest {
|
||||
|
||||
private List<String> fileIds = new ArrayList<>();
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DownloadFileType;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BulkDownloadRequest {
|
||||
|
||||
private List<String> reportTemplateIds = new ArrayList<>();
|
||||
private Set<DownloadFileType> downloadFileTypes = new HashSet<>();
|
||||
private String redactionPreviewColor;
|
||||
private List<String> fileIds = new ArrayList<>();
|
||||
}
|
||||
@ -8,6 +8,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@ -16,8 +17,12 @@ import lombok.NoArgsConstructor;
|
||||
public class Component {
|
||||
|
||||
@JacksonXmlCData
|
||||
@NonNull
|
||||
private String name;
|
||||
@JacksonXmlCData
|
||||
@NonNull
|
||||
private List<ComponentValue> componentValues;
|
||||
@JacksonXmlCData
|
||||
private boolean overridden;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class ComponentMappingMetadataModel {
|
||||
|
||||
String id;
|
||||
String name;
|
||||
String fileName;
|
||||
Integer version;
|
||||
List<String> columnLabels;
|
||||
Integer numberOfLines;
|
||||
String encoding;
|
||||
char delimiter;
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class ComponentMappingSummary {
|
||||
|
||||
String dossierTemplateId;
|
||||
List<ComponentMappingMetadataModel> componentMappingList;
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ComponentOverrideList {
|
||||
|
||||
String dossierTemplateId;
|
||||
String dossierId;
|
||||
String fileId;
|
||||
|
||||
List<Component> componentOverrides = new ArrayList<>();
|
||||
}
|
||||
@ -8,6 +8,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@ -16,10 +17,9 @@ import lombok.NoArgsConstructor;
|
||||
public class ComponentValue {
|
||||
|
||||
@JacksonXmlCData
|
||||
@NonNull
|
||||
String value;
|
||||
@JacksonXmlCData
|
||||
String originalValue;
|
||||
@JacksonXmlCData
|
||||
String valueDescription;
|
||||
@JacksonXmlCData
|
||||
String componentRuleId;
|
||||
|
||||
@ -41,6 +41,10 @@ public class DocuMineDossierRequest {
|
||||
@Schema(description = "The id(s) of members associated to this dossier.")
|
||||
private Set<String> memberIds = new HashSet<>();
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "The id(s) of approvers associated to this dossier.")
|
||||
private Set<String> approverIds = new HashSet<>();
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Id(s) of the word report templates used to generate downloads")
|
||||
private Set<String> reportTemplateIds = new HashSet<>();
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierAttributeType;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DossierAttributeDefinition {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private DossierAttributeType type;
|
||||
private String reportingPlaceholder;
|
||||
private DossierDisplaySettings displaySettings;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class DossierDisplaySettings {
|
||||
|
||||
private boolean editable;
|
||||
private boolean filterable;
|
||||
private boolean displayedInDossierList;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DossierAttributeDefinitionList {
|
||||
|
||||
private List<DossierAttributeDefinition> dossierAttributeDefinitions= new ArrayList<>();
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DossierStatusDefinition {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
private int rank;
|
||||
private String color;
|
||||
private long dossierCount;
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DossierStatusDefinitionList {
|
||||
|
||||
private List<DossierStatusDefinition> dossierStatusDefinitions = new ArrayList<>();
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DownloadFileType;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DownloadRequest {
|
||||
|
||||
private List<String> reportTemplateIds = new ArrayList<>();
|
||||
private Set<DownloadFileType> downloadFileTypes = new HashSet<>();
|
||||
private String redactionPreviewColor;
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DownloadFileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.download.DownloadStatusValue;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DownloadStatus {
|
||||
|
||||
private String id;
|
||||
private String userId;
|
||||
private String filename;
|
||||
private String mimeType;
|
||||
private String errorCause;
|
||||
private DownloadStatusValue status;
|
||||
private OffsetDateTime creationDate;
|
||||
private OffsetDateTime lastDownload;
|
||||
private long fileSize;
|
||||
private String dossierId;
|
||||
private List<String> fileIds = new ArrayList<>();
|
||||
private List<DownloadFileType> downloadFileTypes = new ArrayList<>();
|
||||
private List<String> reportTemplateIds = new ArrayList<>();
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DownloadStatusList {
|
||||
|
||||
List<DownloadStatus> downloadStatus = new ArrayList<>();
|
||||
|
||||
}
|
||||
@ -20,6 +20,7 @@ public class FileAttributeDefinition {
|
||||
private String mappedCsvColumnHeader;
|
||||
private String reportingPlaceholder;
|
||||
private DisplaySettings displaySettings;
|
||||
private boolean includeInCsvExport;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReportTemplate {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private OffsetDateTime createdOn;
|
||||
private boolean multiFile;
|
||||
private boolean preSelect;
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReportTemplateList {
|
||||
|
||||
@Builder.Default
|
||||
private List<ReportTemplate> reportTemplates = new ArrayList<>();
|
||||
|
||||
}
|
||||
@ -13,14 +13,14 @@ import lombok.experimental.FieldDefaults;
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Schema(description = "Shows where to find problems in the uploaded rules file")
|
||||
public class RulesValidationMessage {
|
||||
@Schema(description = "Show where blacklisted keywords are used in the rules file.")
|
||||
public class RulesBlacklistMessage {
|
||||
|
||||
@Schema(description = "The Line where it occurred.")
|
||||
@Schema(description = "The Line where the blacklisted keywords are used.")
|
||||
Integer line;
|
||||
@Schema(description = "The Column where it occurred.")
|
||||
@Schema(description = "The Column where the blacklisted keywords are used.")
|
||||
Integer column;
|
||||
@Schema(description = "The error or warning message.")
|
||||
@Schema(description = "The message containing all blacklisted keywords that were used.")
|
||||
String message;
|
||||
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Schema(description = "Show where deprecated methods are used in the rules file.")
|
||||
public class RulesDeprecationMessage {
|
||||
|
||||
@Schema(description = "The Line where the deprecated method is used.")
|
||||
Integer line;
|
||||
@Schema(description = "The Column where the deprecated method is used.")
|
||||
Integer column;
|
||||
@Schema(description = "The deprecated message, should point to method that should be used instead.")
|
||||
String message;
|
||||
@Schema(description = "The name of the deprecated method.")
|
||||
String methodName;
|
||||
|
||||
}
|
||||
@ -8,15 +8,21 @@ import static com.iqser.red.service.persistence.service.v2.api.external.resource
|
||||
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_PATH;
|
||||
import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_ID_PARAM;
|
||||
import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_ID_PATH_VARIABLE;
|
||||
import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_PATH;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.BulkComponentsRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.Component;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentOverrideList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponentsList;
|
||||
|
||||
@ -29,7 +35,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public interface ComponentResource {
|
||||
|
||||
String PATH = ExternalApiConstants.BASE_PATH + DOSSIER_TEMPLATE_PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DOSSIER_PATH + DOSSIER_ID_PATH_PARAM + FILE_PATH;
|
||||
String PATH = ExternalApiConstants.BASE_PATH + DOSSIER_TEMPLATE_PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE;
|
||||
String FILE_PATH = PATH + DOSSIER_PATH + DOSSIER_ID_PATH_PARAM + FileResource.FILE_PATH;
|
||||
|
||||
String COMPONENTS_PATH = "/components";
|
||||
|
||||
@ -44,8 +51,14 @@ public interface ComponentResource {
|
||||
- false (default): The component object does not contain a field componentDetails.
|
||||
""";
|
||||
|
||||
String OVERRIDES_PATH = "/overrides";
|
||||
String REVERT_PATH = "/revert";
|
||||
|
||||
@GetMapping(value = PATH + FILE_ID_PATH_VARIABLE + COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
|
||||
String COMPONENT_OVERRIDE_PARAM = "componentOverride";
|
||||
String REVERT_OVERRIDE_PARAM = "revertOverride";
|
||||
|
||||
|
||||
@GetMapping(value = FILE_PATH + FILE_ID_PATH_VARIABLE + COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
|
||||
@Operation(summary = "Returns the components for a file", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
FileComponents getComponents(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@ -54,11 +67,53 @@ public interface ComponentResource {
|
||||
@Parameter(name = INCLUDE_DETAILS_PARAM, description = INCLUDE_DETAILS_DESCRIPTION) @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails);
|
||||
|
||||
|
||||
@GetMapping(value = PATH + BULK_COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
|
||||
@GetMapping(value = FILE_PATH + BULK_COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
|
||||
@Operation(summary = "Returns the components for all files of a dossier", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
FileComponentsList getComponentsOfDossier(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@Parameter(name = INCLUDE_DETAILS_PARAM, description = INCLUDE_DETAILS_DESCRIPTION) @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails);
|
||||
|
||||
|
||||
@PostMapping(value = FILE_PATH
|
||||
+ BULK_COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Returns the components for all files of a dossier", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
FileComponentsList getComponentsForFiles(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@Parameter(name = INCLUDE_DETAILS_PARAM, description = INCLUDE_DETAILS_DESCRIPTION) @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails,
|
||||
@RequestBody BulkComponentsRequest bulkComponentsRequest);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = FILE_PATH + FILE_ID_PATH_VARIABLE + OVERRIDES_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Adds overrides for components", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
void addOverride(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@Parameter(name = FILE_ID_PARAM, description = "The identifier of the file that the components are requested for.", required = true) @PathVariable(FILE_ID_PARAM) String fileId,
|
||||
@Parameter(name = COMPONENT_OVERRIDE_PARAM, description = "The object to override the component.", required = true) @RequestBody Component componentOverrideModel);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@GetMapping(value = FILE_PATH + FILE_ID_PATH_VARIABLE + OVERRIDES_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
|
||||
@Operation(summary = "Gets overrides for components", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
ComponentOverrideList getOverrides(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@Parameter(name = FILE_ID_PARAM, description = "The identifier of the file that the components are requested for.", required = true) @PathVariable(FILE_ID_PARAM) String fileId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = FILE_PATH + FILE_ID_PATH_VARIABLE + OVERRIDES_PATH + REVERT_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Reverts overrides for components", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
void revertOverrides(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@Parameter(name = FILE_ID_PARAM, description = "The identifier of the file that the components are requested for.", required = true) @PathVariable(FILE_ID_PARAM) String fileId,
|
||||
@Parameter(name = REVERT_OVERRIDE_PARAM) @RequestBody RevertOverrideRequest revertOverrideRequest);
|
||||
|
||||
}
|
||||
|
||||
@ -18,7 +18,10 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DocuMineDossierRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierAttributes;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatus;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@ -32,11 +35,15 @@ public interface DossierResource {
|
||||
String PATH = ExternalApiConstants.BASE_PATH + DOSSIER_TEMPLATE_PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DOSSIER_PATH;
|
||||
String DOSSIER_ID_PARAM = "dossierId";
|
||||
String DOSSIER_ID_PATH_PARAM = "/{" + DOSSIER_ID_PARAM + "}";
|
||||
String ATTRIBUTES_PATH = "/attributes";
|
||||
String CREATE_DOWNLOAD_PATH = "/create-download";
|
||||
|
||||
String INCLUDE_ACTIVE_PARAM = "includeActive";
|
||||
String INCLUDE_ARCHIVED_PARAM = "includeArchived";
|
||||
String INCLUDE_SOFT_DELETED_PARAM = "includeSoftDeleted";
|
||||
|
||||
String DELETE_PERMANENTLY_PARAM = "deletePermanently";
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@ -72,6 +79,27 @@ public interface DossierResource {
|
||||
@Operation(summary = "Deletes an existing dossier.", description = "Dossiers get soft-deleted unless specified other. A soft-deleted dossier can be restored during a retention period that is configured in the application settings. The default retention period is 96h.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully deleted the dossier."), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
void deleteDossier(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier to retrieve.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId);
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier to retrieve.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@Parameter(name = DELETE_PERMANENTLY_PARAM, description = "A toggle to determine the deletion mode for a dossier: `true`: The dossier will be permanently deleted and can't be restored. `false` (default): Soft-delete, allowing restoration within the application-configured retention period.") @RequestParam(name = DELETE_PERMANENTLY_PARAM, defaultValue = "false", required = false) boolean deletePermanently);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@ResponseBody
|
||||
@PostMapping(value = PATH + DOSSIER_ID_PATH_PARAM + ATTRIBUTES_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Update or set attributes for a specific dossier.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Dossier attributes successfully updated."), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
void setDossierAttributes(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of a dossier template", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of a dossier", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestBody DossierAttributes dossierAttributes);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = PATH + DOSSIER_ID_PATH_PARAM + CREATE_DOWNLOAD_PATH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Initiate the creation of a download package for all files of a dossier.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully started the creation of the download package for all files of the requested dossier."), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
DownloadStatus prepareDossierDownload(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of a dossier template", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of a dossier", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestBody DownloadRequest downloadRequest);
|
||||
|
||||
}
|
||||
|
||||
@ -1,31 +1,41 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierAttributeDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierStatusDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileAttributeDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.RulesValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ReportTemplateList;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinition;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionAddRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionUpdateRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummary;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "429", description = "Too many requests.")})
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@ -35,15 +45,33 @@ public interface DossierTemplateResource {
|
||||
String PATH = ExternalApiConstants.BASE_PATH + DOSSIER_TEMPLATE_PATH;
|
||||
|
||||
String ENTITY_RULES_PATH = "/entity-rules";
|
||||
String DATE_FORMATS_PATH = "/date-formats";
|
||||
String COMPONENT_RULES_PATH = "/component-rules";
|
||||
String COMPONENT_MAPPINGS_PATH = "/component-mappings";
|
||||
String DOSSIER_STATUS_DEFINITIONS_PATH = "/dossier-status-definitions";
|
||||
String DOSSIER_ATTRIBUTE_DEFINITION_PATH = "/dossier-attribute-definitions";
|
||||
|
||||
String FILE_ATTRIBUTE_DEFINITIONS_PATH = "/file-attribute-definitions";
|
||||
String DOSSIER_TEMPLATE_ID_PARAM = "dossierTemplateId";
|
||||
String DOSSIER_TEMPLATE_ID_PATH_VARIABLE = "/{" + DOSSIER_TEMPLATE_ID_PARAM + "}";
|
||||
String REPORT_TEMPLATES_PATH = "/report-templates";
|
||||
|
||||
String RULE_FILE_TYPE_PARAMETER_NAME = "ruleFileType";
|
||||
String COMPONENT_MAPPING_ID_PARAM = "componentMappingId";
|
||||
String COMPONENT_MAPPING_ID_PATH_VARIABLE = "/{" + COMPONENT_MAPPING_ID_PARAM + "}";
|
||||
|
||||
String DRY_RUN_PARAM = "dryRun";
|
||||
String ENCODING_PARAM = "encoding";
|
||||
String DELIMITER_PARAM = "delimiter";
|
||||
String QUOTE_CHAR_PARAM = "quoteChar";
|
||||
String MAPPING_NAME_PARAM = "name";
|
||||
|
||||
String INCLUDE_SOFT_DELETED = "includeSoftDeleted";
|
||||
String COMPONENT_ID_PARAM = "componentId";
|
||||
String COMPONENT_ID_PATH = "/{" + COMPONENT_ID_PARAM + "}";
|
||||
String COMPONENT_IDS = "componentIds";
|
||||
String COMPONENT_PATH = "/component-definitions";
|
||||
String REORDER_PATH = "/reorder";
|
||||
String RESTORE_PATH = "/restore";
|
||||
|
||||
|
||||
@GetMapping(value = PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ -61,10 +89,10 @@ public interface DossierTemplateResource {
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + ENTITY_RULES_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Upload a component or entity rules file in drools format for a specific DossierTemplate.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found."), @ApiResponse(responseCode = "422", description = "Uploaded rules could not be verified.")})
|
||||
ResponseEntity<RulesValidationResponse> uploadEntityRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun);
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found."), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified."), @ApiResponse(responseCode = "422", description = "Uploaded rules could not be compiled.")})
|
||||
ResponseEntity<DroolsValidationResponse> uploadEntityRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ -80,10 +108,10 @@ public interface DossierTemplateResource {
|
||||
+ DOSSIER_TEMPLATE_ID_PATH_VARIABLE
|
||||
+ COMPONENT_RULES_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Upload a component or entity rules file in drools format for a specific DossierTemplate.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found."), @ApiResponse(responseCode = "422", description = "Uploaded rules could not be verified.")})
|
||||
ResponseEntity<RulesValidationResponse> uploadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun);
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found."), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified."), @ApiResponse(responseCode = "422", description = "Uploaded rules could not be compiled.")})
|
||||
ResponseEntity<DroolsValidationResponse> uploadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ -94,9 +122,152 @@ public interface DossierTemplateResource {
|
||||
ResponseEntity<?> downloadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DATE_FORMATS_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Upload a date formats file for a specific DossierTemplate.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Date formats upload successful."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found."), @ApiResponse(responseCode = "400", description = "Uploaded date formats could not be verified."), @ApiResponse(responseCode = "422", description = "Uploaded date formats file could not be parsed.")})
|
||||
ResponseEntity<?> uploadDateFormats(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Returns file containing the currently used date formats.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DATE_FORMATS_PATH)
|
||||
ResponseEntity<?> downloadDateFormats(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
|
||||
|
||||
|
||||
@Operation(summary = "Get the file attribute definitions of a DossierTemplate.", description = "None")
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + FILE_ATTRIBUTE_DEFINITIONS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "File attribute definitions returned successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
|
||||
FileAttributeDefinitionList getFileAttributeDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
|
||||
|
||||
|
||||
@Operation(summary = "Get the component mapping summaries of a DossierTemplate.", description = "None")
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Component mapping views returned successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
|
||||
ComponentMappingSummary getComponentMappingSummaries(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
|
||||
|
||||
|
||||
@Operation(summary = "Upload a new component mapping to a DossierTemplate.", description = "None")
|
||||
@PostMapping(value = PATH
|
||||
+ DOSSIER_TEMPLATE_ID_PATH_VARIABLE
|
||||
+ COMPONENT_MAPPINGS_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Component mapping uploaded successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
|
||||
ComponentMappingMetadataModel uploadMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = MAPPING_NAME_PARAM, description = "String of what the mapping should be accessible under. If left empty, the name of the file without the ending will be used as name.") @RequestParam(value = MAPPING_NAME_PARAM, required = false, defaultValue = "") String name,
|
||||
@Parameter(name = ENCODING_PARAM, description = "The encoding of the file. Default is UTF-8.") @RequestParam(value = ENCODING_PARAM, required = false, defaultValue = "UTF-8") String encoding,
|
||||
@Parameter(name = DELIMITER_PARAM, description = "The delimiter used in the file. Default is ','") @RequestParam(value = DELIMITER_PARAM, required = false, defaultValue = ",") String delimiter,
|
||||
@Parameter(name = QUOTE_CHAR_PARAM, description = "The quote char used in the file. Default is '\"'") @RequestParam(value = QUOTE_CHAR_PARAM, required = false, defaultValue = "\"") String quoteChar);
|
||||
|
||||
|
||||
@Operation(summary = "Update an existing component mapping of a DossierTemplate.", description = "None")
|
||||
@PutMapping(value = PATH
|
||||
+ DOSSIER_TEMPLATE_ID_PATH_VARIABLE
|
||||
+ COMPONENT_MAPPINGS_PATH
|
||||
+ COMPONENT_MAPPING_ID_PATH_VARIABLE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Component mapping updated successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
|
||||
ComponentMappingMetadataModel updateMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId,
|
||||
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
|
||||
@Parameter(name = MAPPING_NAME_PARAM, description = "String of what the mapping should be accessible under. If left empty, the name of the file without the ending will be used as name.") @RequestParam(value = MAPPING_NAME_PARAM, required = false, defaultValue = "") String name,
|
||||
@Parameter(name = ENCODING_PARAM, description = "The encoding of the file. Default is UTF-8.") @RequestParam(value = ENCODING_PARAM, required = false, defaultValue = "UTF-8") String encoding,
|
||||
@Parameter(name = DELIMITER_PARAM, description = "The delimiter used in the file. Default is ','") @RequestParam(value = DELIMITER_PARAM, required = false, defaultValue = ",") String delimiter,
|
||||
@Parameter(name = QUOTE_CHAR_PARAM, description = "The quote char used in the file. Default is '\"'") @RequestParam(value = QUOTE_CHAR_PARAM, required = false, defaultValue = "\"") String quoteChar);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@Operation(summary = "Returns file containing the specified mapping as a file.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH + COMPONENT_MAPPING_ID_PATH_VARIABLE)
|
||||
ResponseEntity<?> downloadMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@Operation(summary = "Deletes a specified mapping.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
|
||||
@DeleteMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH + COMPONENT_MAPPING_ID_PATH_VARIABLE)
|
||||
ResponseEntity<?> deleteMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId);
|
||||
|
||||
|
||||
@Operation(summary = "Returns the list of all existing dossier status definitions.", description = "None")
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DOSSIER_STATUS_DEFINITIONS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully returned the dossier status definitions for the specified dossier template."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
|
||||
DossierStatusDefinitionList getDossierStatusDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
|
||||
|
||||
|
||||
@Operation(summary = "Returns the list of all existing dossier attribute definitions.", description = "None")
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DOSSIER_ATTRIBUTE_DEFINITION_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully returned the dossier attribute definitions for the specified dossier template."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
|
||||
DossierAttributeDefinitionList getDossierAttributeDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@Operation(summary = "Create new components", description = "Create new components for a given dossier template.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Created")})
|
||||
@PostMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<ComponentDefinition> createComponents(@Valid @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@RequestBody List<ComponentDefinitionAddRequest> componentDefinitionUpdateRequests);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Get all components", description = "Get all components for a given dossier template.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<ComponentDefinition> getComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = INCLUDE_SOFT_DELETED, description = "Include files which are soft deleted. Default is false.") @RequestParam(value = INCLUDE_SOFT_DELETED, defaultValue = "false") boolean includeSoftDeleted);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Get a component by ID", description = "Get specific details for a component by ID.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified component is not found.")})
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH + COMPONENT_ID_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
ComponentDefinition getComponent(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(COMPONENT_ID_PARAM) String componentId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Update components", description = "Update existing components.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@PutMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<ComponentDefinition> updateComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Valid @RequestBody List<ComponentDefinitionUpdateRequest> componentDefinitionUpdateRequests);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Delete components", description = "Delete existing components by their IDs.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "No Content")})
|
||||
@DeleteMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH)
|
||||
void deleteComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @RequestParam(name = COMPONENT_IDS) List<String> componentIds);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Restore components", description = "Restore previously soft deleted components based on their IDs.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@PutMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH + RESTORE_PATH)
|
||||
List<ComponentDefinition> restoreComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @RequestParam(name = COMPONENT_IDS) List<String> componentIds);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Reorder components", description = "Reorder components based on their rank.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH + REORDER_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<ComponentDefinition> reorderComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @RequestParam(name = COMPONENT_IDS) List<String> componentIds);
|
||||
|
||||
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + REPORT_TEMPLATES_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Returns the list of all available report templates", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully returned the report templates for the specified dossier template."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
|
||||
ReportTemplateList getReportTemplates(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.resource;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatus;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatusList;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "429", description = "Too many requests.")})
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public interface DownloadResource {
|
||||
|
||||
String DOWNLOADS_PATH = "/downloads";
|
||||
String PATH = ExternalApiConstants.BASE_PATH + DOWNLOADS_PATH;
|
||||
String DOWNLOAD_ID_PARAM = "downloadId";
|
||||
String DOWNLOAD_ID_PATH_PARAM = "/{" + DOWNLOAD_ID_PARAM + "}";
|
||||
String DOWNLOAD_PATH = "/download";
|
||||
|
||||
|
||||
@GetMapping(value = PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Get the list of downloads for the current user", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "List of all downloads of the current users successfully retrieved.")})
|
||||
DownloadStatusList getDownloadStatusList();
|
||||
|
||||
|
||||
@GetMapping(value = PATH + DOWNLOAD_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Get the status for a specific download of the current user", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Status of the download successfully retrieved.")})
|
||||
DownloadStatus getDownloadStatus(@Parameter(name = DOWNLOAD_ID_PARAM, description = "The identifier for the file to download.", required = true) @PathVariable(DOWNLOAD_ID_PARAM) String downloadId);
|
||||
|
||||
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@DeleteMapping(value = PATH + DOWNLOAD_ID_PATH_PARAM)
|
||||
@Operation(summary = "Deletes a specific download.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Download deletion successful. This confirms the absence of the specified download, irrespective of its previous existence.")})
|
||||
void deleteDownload(@Parameter(name = DOWNLOAD_ID_PARAM, description = "The identifier for the file to download.", required = true) @PathVariable(DOWNLOAD_ID_PARAM) String downloadId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@Operation(summary = "Download the download package.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully downloaded the requested file."), @ApiResponse(responseCode = "404", description = "Download not found. This happens if the requested download does not exist for the current user.")})
|
||||
@GetMapping(value = PATH + DOWNLOAD_ID_PATH_PARAM + DOWNLOAD_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE})
|
||||
void download(@Parameter(name = DOWNLOAD_ID_PARAM, description = "The identifier for the file to download.", required = true) @PathVariable(DOWNLOAD_ID_PARAM) String downloadId);
|
||||
|
||||
}
|
||||
@ -26,6 +26,9 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileUploadResult;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.BulkDownloadRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatus;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileDeleteRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileStatusList;
|
||||
|
||||
@ -42,7 +45,10 @@ public interface FileResource {
|
||||
String PATH = ExternalApiConstants.BASE_PATH + DOSSIER_TEMPLATE_PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DOSSIER_PATH + DOSSIER_ID_PATH_PARAM + FILE_PATH;
|
||||
String BULK_DELETE_PATH = "/bulk/delete";
|
||||
String FILE_ATTRIBUTES_PATH = "/attributes";
|
||||
String CREATE_DOWNLOAD_PATH = "/create-download";
|
||||
String BULK_CREATE_DOWNLOAD_PATH = "/bulk/create-download";
|
||||
String KEEP_MANUAL_CHANGES_PARAM = "keepManualChanges";
|
||||
String DISABLE_AUTOMATIC_ANALYSIS_PARAM = "disableAutomaticAnalysis";
|
||||
String DELETE_PERMANENTLY_PARAM = "deletePermanently";
|
||||
String FILE_PARAM = "file";
|
||||
String FILE_ID_PARAM = "fileId";
|
||||
@ -57,7 +63,8 @@ public interface FileResource {
|
||||
FileUploadResult upload(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier to where the file is to be uploaded.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@Parameter(name = FILE_PARAM, description = "The file to be uploaded.", required = true) @Schema(type = "string", format = "binary", name = "file") @RequestPart(name = FILE_PARAM) MultipartFile file,
|
||||
@Parameter(name = KEEP_MANUAL_CHANGES_PARAM, description = "A Toggle to keep manual changes: Manual changes are manually added annotations or manipulations on existing ones. If set to `true` the system keeps the manual changes on re-uploading (overwriting) the file.") @RequestParam(value = KEEP_MANUAL_CHANGES_PARAM, required = false, defaultValue = "false") boolean keepManualChanges);
|
||||
@Parameter(name = KEEP_MANUAL_CHANGES_PARAM, description = "A Toggle to keep manual changes: Manual changes are manually added annotations or manipulations on existing ones. If set to `true` the system keeps the manual changes on re-uploading (overwriting) the file.") @RequestParam(value = KEEP_MANUAL_CHANGES_PARAM, required = false, defaultValue = "false") boolean keepManualChanges,
|
||||
@Parameter(name = DISABLE_AUTOMATIC_ANALYSIS_PARAM, description = "Disables automatic redaction for the uploaded file, imports only imported redactions") @RequestParam(value = DISABLE_AUTOMATIC_ANALYSIS_PARAM, required = false, defaultValue = "false") boolean disableAutomaticAnalysis);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ -103,12 +110,34 @@ public interface FileResource {
|
||||
@Parameter(name = DELETE_PERMANENTLY_PARAM, description = "A Toggle to permanently delete the file: If `true` the file will be deleted permanently, i.e. in contrast to a soft-delete (value is `false`) the file cannot be restored anymore. This can be applied also on previously soft-deleted files.") @RequestParam(name = DELETE_PERMANENTLY_PARAM, defaultValue = "false", required = false) boolean deletePermanently);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Set file attributes to an existing file", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK")})
|
||||
@PostMapping(value = PATH + FILE_ID_PATH_VARIABLE + FILE_ATTRIBUTES_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
void setFileAttributes(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@Parameter(name = FILE_ID_PARAM, description = "The identifier of the file of which the file attributes are set.", required = true) @PathVariable(FILE_ID_PARAM) String fileId,
|
||||
@RequestBody FileAttributes fileAttributes);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = PATH + FILE_ID_PATH_VARIABLE + CREATE_DOWNLOAD_PATH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Initiate the creation of a download package for a single file of a dossier.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully started the creation of the download package for the requested file."), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
DownloadStatus prepareFileDownload(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of a dossier template", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of a dossier", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@Parameter(name = FILE_ID_PARAM, description = "The identifier of a file", required = true) @PathVariable(FILE_ID_PARAM) String fileId,
|
||||
@RequestBody DownloadRequest downloadRequest);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = PATH + BULK_CREATE_DOWNLOAD_PATH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Initiate the creation of a download package for specific files within a dossier.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully started the creation of the download package for the requested files."), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
DownloadStatus prepareBulkDownload(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of a dossier template", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of a dossier", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
|
||||
@RequestBody BulkDownloadRequest bulkDownloadRequest);
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id("com.iqser.red.service.java-conventions")
|
||||
id("io.freefair.lombok") version "8.4"
|
||||
id("io.freefair.lombok") version "8.6"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
package com.iqser.red.service.persistence.v1.internal.api.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.DateFormatsEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.RulesTimeoutDetectedException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DateFormatsPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.internal.resources.DateFormatsResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class DateFormatsInternalController implements DateFormatsResource {
|
||||
|
||||
private final DateFormatsPersistenceService dateFormatsPersistenceService;
|
||||
|
||||
|
||||
@Override
|
||||
public JSONPrimitive<String> getDateFormats(String dossierTemplateId) {
|
||||
|
||||
DateFormatsEntity dateFormats = getDateFormatsForDossierTemplate(dossierTemplateId);
|
||||
return new JSONPrimitive<>(dateFormats.getValue());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getVersion(String dossierTemplateId) {
|
||||
|
||||
DateFormatsEntity dateFormats = getDateFormatsForDossierTemplate(dossierTemplateId);
|
||||
return dateFormats.getVersion();
|
||||
}
|
||||
|
||||
|
||||
private DateFormatsEntity getDateFormatsForDossierTemplate(String dossierTemplateId) {
|
||||
|
||||
var dateFormatsOptional = dateFormatsPersistenceService.getDateFormats(dossierTemplateId);
|
||||
if (dateFormatsOptional.isEmpty()) {
|
||||
throw new NotFoundException(String.format("No date formats file found for dossierTemplateId %s", dossierTemplateId));
|
||||
}
|
||||
return dateFormatsOptional.get();
|
||||
}
|
||||
|
||||
}
|
||||
@ -32,17 +32,39 @@ public class DictionaryInternalController implements DictionaryResource {
|
||||
|
||||
@Override
|
||||
public List<Type> getAllTypesForDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
|
||||
@RequestParam(value = FROM_VERSION_PARAM, required = false) Long fromVersion,
|
||||
@RequestParam(value = INCLUDE_DELETED_PARAMETER_NAME, required = false, defaultValue = "false") boolean includeDeleted) {
|
||||
|
||||
return convert(dictionaryPersistenceService.getAllTypesForDossierTemplate(dossierTemplateId, includeDeleted), Type.class);
|
||||
var targets = convert(dictionaryPersistenceService.getAllTypesForDossierTemplate(dossierTemplateId, includeDeleted), Type.class);
|
||||
setEntriesForTypes(fromVersion, targets);
|
||||
return targets;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Type> getAllTypesForDossier(@PathVariable(DOSSIER_ID_PARAMETER_NAME) String dossierId,
|
||||
@RequestParam(value = FROM_VERSION_PARAM, required = false) Long fromVersion,
|
||||
@RequestParam(value = INCLUDE_DELETED_PARAMETER_NAME, required = false, defaultValue = "false") boolean includeDeleted) {
|
||||
|
||||
return convert(dictionaryPersistenceService.getAllTypesForDossier(dossierId, includeDeleted), Type.class);
|
||||
var targets = convert(dictionaryPersistenceService.getAllTypesForDossier(dossierId, includeDeleted), Type.class);
|
||||
setEntriesForTypes(fromVersion, targets);
|
||||
return targets;
|
||||
}
|
||||
|
||||
|
||||
private void setEntriesForTypes(Long fromVersion, List<Type> targets) {
|
||||
|
||||
targets.forEach(target -> {
|
||||
setEntriesForType(target.getTypeId(), target, fromVersion != null ? fromVersion : -1);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void setEntriesForType(String typeId, Type target, Long fromVersion) {
|
||||
|
||||
target.setEntries(convert(entryPersistenceService.getEntries(typeId, DictionaryEntryType.ENTRY, fromVersion), DictionaryEntry.class));
|
||||
target.setFalsePositiveEntries(convert(entryPersistenceService.getEntries(typeId, DictionaryEntryType.FALSE_POSITIVE, fromVersion), DictionaryEntry.class));
|
||||
target.setFalseRecommendationEntries(convert(entryPersistenceService.getEntries(typeId, DictionaryEntryType.FALSE_RECOMMENDATION, fromVersion), DictionaryEntry.class));
|
||||
}
|
||||
|
||||
|
||||
@ -51,9 +73,7 @@ public class DictionaryInternalController implements DictionaryResource {
|
||||
|
||||
var entity = dictionaryPersistenceService.getType(typeId, true);
|
||||
var target = convert(entity, Type.class);
|
||||
target.setEntries(convert(entryPersistenceService.getEntries(typeId, DictionaryEntryType.ENTRY, fromVersion), DictionaryEntry.class));
|
||||
target.setFalsePositiveEntries(convert(entryPersistenceService.getEntries(typeId, DictionaryEntryType.FALSE_POSITIVE, fromVersion), DictionaryEntry.class));
|
||||
target.setFalseRecommendationEntries(convert(entryPersistenceService.getEntries(typeId, DictionaryEntryType.FALSE_RECOMMENDATION, fromVersion), DictionaryEntry.class));
|
||||
setEntriesForType(typeId, target, fromVersion);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierAttributeConfigEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierAttributeConfigPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.DossierAttributeConfigMapper;
|
||||
import com.iqser.red.service.persistence.service.v1.api.internal.resources.DossierAttributesConfigResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierAttributeConfig;
|
||||
|
||||
@ -27,7 +28,7 @@ public class DossierAttributesConfigInternalController implements DossierAttribu
|
||||
@Override
|
||||
public List<DossierAttributeConfig> getDossierAttributes(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId) {
|
||||
|
||||
return convert(dossierAttributeConfigPersistenceService.getDossierAttributes(dossierTemplateId), DossierAttributeConfig.class);
|
||||
return convert(dossierAttributeConfigPersistenceService.getDossierAttributes(dossierTemplateId), DossierAttributeConfig.class, new DossierAttributeConfigMapper());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicC
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierTemplateImportService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.dataexchange.service.DossierTemplateImportService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.internal.resources.DossierTemplateResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplate;
|
||||
|
||||
@ -22,7 +22,7 @@ public class EntityLogInternalController implements EntityLogResource {
|
||||
@Override
|
||||
public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
|
||||
@RequestParam(value = "excludedType", required = false, defaultValue = "") List<String> excludedTypes,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
|
||||
return entityLogService.getEntityLog(dossierId, fileId, excludedTypes, includeUnprocessed);
|
||||
|
||||
@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileAttributeConfigPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.FileAttributeConfigMapper;
|
||||
import com.iqser.red.service.persistence.service.v1.api.internal.resources.FileAttributesConfigResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileAttributeConfig;
|
||||
|
||||
@ -25,7 +26,7 @@ public class FileAttributesConfigInternalController implements FileAttributesCon
|
||||
@Override
|
||||
public List<FileAttributeConfig> getFileAttributeConfigs(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId) {
|
||||
|
||||
return convert(fileAttributeConfigPersistenceService.getFileAttributes(dossierTemplateId), FileAttributeConfig.class);
|
||||
return convert(fileAttributeConfigPersistenceService.getFileAttributes(dossierTemplateId), FileAttributeConfig.class, new FileAttributeConfigMapper());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration;
|
||||
@ -39,7 +38,7 @@ public class FileStatusProcessingUpdateInternalController implements FileStatusP
|
||||
fileStatusProcessingUpdateService.preprocessingFailed(dossierId,
|
||||
fileId,
|
||||
new FileErrorInfo("preprocessing failed",
|
||||
MessagingConfiguration.PRE_PROCESSING_DLQ,
|
||||
MessagingConfiguration.PREPROCESSING_DLQ,
|
||||
"pdftron-service",
|
||||
OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)));
|
||||
}
|
||||
@ -57,6 +56,7 @@ public class FileStatusProcessingUpdateInternalController implements FileStatusP
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public void ocrSuccessful(@PathVariable(DOSSIER_ID_PARAM) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
fileStatusProcessingUpdateService.ocrSuccessful(dossierId, fileId);
|
||||
@ -81,12 +81,14 @@ public class FileStatusProcessingUpdateInternalController implements FileStatusP
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public void ocrProcessing(@PathVariable(DOSSIER_ID_PARAM) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
fileStatusProcessingUpdateService.ocrProcessing(dossierId, fileId);
|
||||
fileStatusProcessingUpdateService.ocrProcessing(fileId);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public void ocrFailed(@PathVariable(DOSSIER_ID_PARAM) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
fileStatusProcessingUpdateService.ocrFailed(dossierId,
|
||||
@ -98,6 +100,7 @@ public class FileStatusProcessingUpdateInternalController implements FileStatusP
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public void ocrFailed(@PathVariable(DOSSIER_ID_PARAM) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody FileErrorInfo fileErrorInfo) {
|
||||
|
||||
fileStatusProcessingUpdateService.ocrFailed(dossierId, fileId, fileErrorInfo);
|
||||
@ -121,7 +124,7 @@ public class FileStatusProcessingUpdateInternalController implements FileStatusP
|
||||
fileStatusProcessingUpdateService.indexingFailed(dossierId,
|
||||
fileId,
|
||||
new FileErrorInfo("indexing failed",
|
||||
MessagingConfiguration.INDEXING_DQL,
|
||||
MessagingConfiguration.INDEXING_DLQ,
|
||||
"search-service",
|
||||
OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)));
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user