233 Commits
Author SHA1 Message Date
backdev f6d45e5dd2 Add file info public
Test Workflow / test (push) Has been cancelled
2026-06-02 12:27:45 +07:00
backdev 1a2eaaacab Add file info public
Test Workflow / test (push) Has been cancelled
2026-06-02 12:11:35 +07:00
backdev 74dfbe2ae4 Add file info public
Test Workflow / test (push) Has been cancelled
2026-06-02 12:06:56 +07:00
backdev 45f7e3d0bf Add file info public
Test Workflow / test (push) Has been cancelled
2026-06-02 12:04:01 +07:00
backdev 5c438c466f NCBACK-162
Test Workflow / test (push) Has been cancelled
2026-06-01 15:51:42 +07:00
backdev 5427603f89 NCBACK-162
Test Workflow / test (push) Has been cancelled
2026-06-01 15:25:36 +07:00
backdev ab4c60f4b9 NCBACK-162
Test Workflow / test (push) Has been cancelled
2026-06-01 15:07:11 +07:00
backdev 184f3a730c NCBACK-162
Test Workflow / test (push) Has been cancelled
2026-06-01 14:49:36 +07:00
backdev b107b805fc NCBACK-162
Test Workflow / test (push) Has been cancelled
2026-06-01 13:53:18 +07:00
backdev b406b50013 NCBACK-162
Test Workflow / test (push) Has been cancelled
2026-06-01 13:44:03 +07:00
backdev 5e494ffc4b NCBACK-162
Test Workflow / test (push) Has been cancelled
2026-05-29 18:17:04 +07:00
backdev bc26b39d86 dev check fileName
Test Workflow / test (push) Has been cancelled
2026-05-29 12:12:26 +07:00
backdev 9423a44e17 dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-28 14:26:06 +07:00
backdev 1f49c49679 dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-28 13:38:35 +07:00
backdev be779ec496 dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-28 13:07:09 +07:00
backdev 6f2d8320dc dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-28 12:44:51 +07:00
backdev ea33e9cfe3 dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-28 12:18:46 +07:00
backdev a2e94b744c dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-28 11:23:12 +07:00
backdev de2a7f83fd dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-27 18:52:46 +07:00
backdev 1ac6d6f1b0 dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-27 17:47:12 +07:00
backdev d82ee69d6f dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-27 17:35:47 +07:00
backdev 6555f4c0c2 dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-27 16:44:07 +07:00
backdev c83dc10125 dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-27 16:31:08 +07:00
backdev 71cd0ebf10 dev add tariff info and control
Test Workflow / test (push) Has been cancelled
2026-05-27 16:15:36 +07:00
backdev ca9a7478f4 dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-27 14:31:40 +07:00
backdev ea763edbec dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-27 11:31:04 +07:00
backdev 357ca3ec62 dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-27 11:21:33 +07:00
backdev cb8a564afe dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-27 11:02:35 +07:00
backdev 398bfe74bb dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-27 10:35:28 +07:00
backdev 1e8e1f48db dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-26 16:33:08 +07:00
backdev 8a4f299941 dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-26 16:17:16 +07:00
backdev 9891b1d9b2 dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-26 15:37:38 +07:00
backdev e26b5928a4 dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-26 15:17:58 +07:00
backdev 2dc9a760bc dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-26 14:56:35 +07:00
backdev 646d6fa11d dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-26 14:47:56 +07:00
backdev 16791d35de dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-26 13:21:01 +07:00
backdev 4a85e415a7 dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-26 11:45:43 +07:00
backdev 85f8528b0c dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-25 19:08:41 +07:00
backdev 31d257c9bb dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-25 18:31:41 +07:00
backdev b87a4aff39 dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-25 17:20:40 +07:00
backdev 859a95fda7 dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-25 16:39:19 +07:00
backdev 7ec130e006 dev add complaint all info with pagination
Test Workflow / test (push) Has been cancelled
2026-05-25 15:20:50 +07:00
backdev 8ee60229f0 dev add User info for internal-data
Test Workflow / test (push) Has been cancelled
2026-05-25 14:51:09 +07:00
backdev d55b1620d5 dev add statistic complaints by status
Test Workflow / test (push) Has been cancelled
2026-05-25 14:16:39 +07:00
backdev 6929060661 dev add statistic complaints by status
Test Workflow / test (push) Has been cancelled
2026-05-25 12:57:22 +07:00
backdev 670f14e955 dev add statistic complaints by status
Test Workflow / test (push) Has been cancelled
2026-05-25 12:38:20 +07:00
backdev 1536dbc845 dev fix download with cyrrilic symbols
Test Workflow / test (push) Has been cancelled
2026-05-22 16:57:03 +07:00
backdev 59c1b30669 dev fix download with cyrrilic symbols
Test Workflow / test (push) Has been cancelled
2026-05-22 16:47:32 +07:00
backdev 992cc1747c dev fix download with cyrrilic symbols
Test Workflow / test (push) Has been cancelled
2026-05-22 16:37:49 +07:00
backdev b557b851e4 dev fix download with cyrrilic symbols
Test Workflow / test (push) Has been cancelled
2026-05-22 15:20:34 +07:00
backdev 9713f383a6 dev fix download with cyrrilic symbols
Test Workflow / test (push) Has been cancelled
2026-05-22 15:12:21 +07:00
backdev 34d5f159a4 dev fix download with cyrrilic symbols
Test Workflow / test (push) Has been cancelled
2026-05-22 15:01:43 +07:00
backdev 71e410aef5 dev fix download with cyrrilic symbols
Test Workflow / test (push) Has been cancelled
2026-05-22 14:55:51 +07:00
backdev b143b29a78 dev fix download with cyrrilic symbols
Test Workflow / test (push) Has been cancelled
2026-05-22 14:50:15 +07:00
backdev 9afe09ccc5 dev add cache for search
Test Workflow / test (push) Has been cancelled
2026-05-21 17:05:57 +07:00
backdev e20e4f6b48 dev add cache for search
Test Workflow / test (push) Has been cancelled
2026-05-21 16:55:21 +07:00
backdev 246d55da55 dev add cache for search
Test Workflow / test (push) Has been cancelled
2026-05-21 16:42:50 +07:00
backdev 81130fc238 dev add cache for search
Test Workflow / test (push) Has been cancelled
2026-05-21 16:26:07 +07:00
backdev 942e4d4926 dev add cache for search
Test Workflow / test (push) Has been cancelled
2026-05-21 16:15:50 +07:00
backdev cf2aefe6c3 dev add cache for search
Test Workflow / test (push) Has been cancelled
2026-05-21 16:06:47 +07:00
backdev ab796932e6 dev fields for notion
Test Workflow / test (push) Has been cancelled
2026-05-21 14:38:33 +07:00
backdev 55081d51a3 dev fields for notion
Test Workflow / test (push) Has been cancelled
2026-05-21 14:26:50 +07:00
backdev 0c522e2faf dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-21 13:15:11 +07:00
backdev 5c0a0c146b dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 17:10:20 +07:00
backdev 42e8648f53 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 17:00:52 +07:00
backdev e03c9ff0ff dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 16:34:16 +07:00
backdev 3a1f4ea9d9 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 16:22:22 +07:00
backdev 24bae18311 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 16:04:33 +07:00
backdev 7845304f87 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 15:54:29 +07:00
backdev 4dc479e31b dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 15:45:40 +07:00
backdev e633d43a74 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 15:36:55 +07:00
backdev 31713550ce dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 14:55:43 +07:00
backdev 2aac3bbdf4 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 14:35:23 +07:00
backdev 6415053840 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 14:30:56 +07:00
backdev 772cf9f40f dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 14:22:40 +07:00
backdev 20911982a6 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 13:08:55 +07:00
backdev 82e84514e4 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 12:59:17 +07:00
backdev 9dd1f8e6c8 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 12:22:39 +07:00
backdev 73ef7a57a3 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-19 12:11:14 +07:00
backdev 284bde0e27 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-18 15:13:16 +07:00
backdev 218582958c dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-18 14:01:02 +07:00
backdev 16620213c7 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-18 13:52:41 +07:00
backdev 0e0fac02a8 dev check violation for lawcase,complaint
Test Workflow / test (push) Has been cancelled
2026-05-18 13:25:53 +07:00
backdev 57a39d0cb0 dev add tarriff description
Test Workflow / test (push) Has been cancelled
2026-05-15 16:52:55 +07:00
backdev df38da6d5f dev add tarriff description
Test Workflow / test (push) Has been cancelled
2026-05-15 16:06:31 +07:00
backdev cbff850da6 dev add tarriff description
Test Workflow / test (push) Has been cancelled
2026-05-15 15:52:50 +07:00
backdev afe78f74f2 dev add tarriff description
Test Workflow / test (push) Has been cancelled
2026-05-15 15:41:24 +07:00
backdev c0818146bc dev add tarriff description
Test Workflow / test (push) Has been cancelled
2026-05-15 15:29:07 +07:00
backdev a4928395b9 dev add tarriff description
Test Workflow / test (push) Has been cancelled
2026-05-15 14:44:54 +07:00
backdev 7c7ad61397 dev add field locale for get info for view doc
Test Workflow / test (push) Has been cancelled
2026-05-15 13:37:15 +07:00
backdev dfc24b77c4 dev add field locale for get info for view doc
Test Workflow / test (push) Has been cancelled
2026-05-15 13:27:29 +07:00
backdev 8c8ae0eb3c dev add field locale for get info for view doc
Test Workflow / test (push) Has been cancelled
2026-05-15 13:17:47 +07:00
backdev ae81c42b89 dev add field locale for get info for view doc
Test Workflow / test (push) Has been cancelled
2026-05-15 13:07:16 +07:00
backdev cfe3520bad dev add field locale for get info for view doc
Test Workflow / test (push) Has been cancelled
2026-05-15 12:56:56 +07:00
backdev b0c66720b0 dev add field locale for get info for view doc
Test Workflow / test (push) Has been cancelled
2026-05-15 12:40:26 +07:00
backdev 0c373acc7f dev add field locale for get info for view doc
Test Workflow / test (push) Has been cancelled
2026-05-15 10:49:44 +07:00
backdev 59e9de2684 dev add field locale for get info for view doc
Test Workflow / test (push) Has been cancelled
2026-05-14 13:01:40 +07:00
backdev 5dc3bb7157 dev add field locale for get info for view doc
Test Workflow / test (push) Has been cancelled
2026-05-14 12:44:19 +07:00
backdev 48cdca56a2 dev add check name with locale
Test Workflow / test (push) Has been cancelled
2026-05-14 12:28:52 +07:00
backdev 59909c05c3 dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-14 11:44:08 +07:00
backdev 675c93c0c6 dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 16:31:55 +07:00
backdev cc77f481dc dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 16:21:04 +07:00
backdev 51feca36d0 dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 16:00:35 +07:00
backdev 17850710b5 dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 15:43:43 +07:00
backdev de8120c737 dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 15:32:55 +07:00
backdev 2319dd498f dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 15:19:45 +07:00
backdev b77efcbce5 dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 14:27:01 +07:00
backdev a6e73be032 dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 14:15:54 +07:00
backdev cda829829c dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 14:03:15 +07:00
backdev 48c14d475d dev add context for notifcations
Test Workflow / test (push) Has been cancelled
2026-05-13 13:39:02 +07:00
backdev 0546f6acd5 dev add user info method by id
Test Workflow / test (push) Has been cancelled
2026-05-13 07:59:28 +07:00
backdev 807a8e1d53 dev add user info method by id
Test Workflow / test (push) Has been cancelled
2026-05-13 07:44:24 +07:00
backdev 0314618db5 dev add user info method by id
Test Workflow / test (push) Has been cancelled
2026-05-12 16:15:23 +07:00
backdev 6bc6592f37 dev add user info method by id
Test Workflow / test (push) Has been cancelled
2026-05-12 14:22:56 +07:00
backdev 4d8d3d4df2 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-09 09:58:54 +07:00
backdev 153a875b16 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 21:07:32 +07:00
backdev 01ba4c3892 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 15:34:57 +07:00
backdev 6565c18958 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 15:19:17 +07:00
backdev f433b4dc01 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 15:05:17 +07:00
backdev 891a900a53 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 14:56:15 +07:00
backdev 96a329cc48 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 14:35:15 +07:00
backdev d506b1cdaf dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 14:09:26 +07:00
backdev ed8eb25ec1 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 13:58:40 +07:00
backdev ec8f3af710 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 12:10:38 +07:00
backdev 394259c2c7 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 11:57:29 +07:00
backdev ff44763f88 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-08 11:42:59 +07:00
backdev 9dd174eb60 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-07 12:49:01 +07:00
backdev 957b10c5b9 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-07 11:35:04 +07:00
backdev 89124a0a73 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-07 11:24:29 +07:00
backdev b864d7e9bd dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 14:30:01 +07:00
backdev 5c918d48ad dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 14:19:30 +07:00
backdev 0d943da120 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 14:09:15 +07:00
backdev af4e4717d1 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 13:59:40 +07:00
backdev d0df78730f dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 13:49:16 +07:00
backdev ef22693691 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 13:29:13 +07:00
backdev b09e4e3bdb dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 13:08:34 +07:00
backdev f88b6fd353 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 13:07:52 +07:00
backdev d23df37b45 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 12:59:38 +07:00
backdev 8b8db46c29 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 12:45:00 +07:00
backdev 3fd4cbeab5 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-06 12:28:07 +07:00
backdev 367af98994 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 15:41:05 +07:00
backdev ba89406417 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 15:31:49 +07:00
backdev d2b94802de dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 14:53:25 +07:00
backdev d98a5ce692 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 14:43:28 +07:00
backdev cdc45e400d dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 14:36:30 +07:00
backdev c9e95edf1d dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 14:22:17 +07:00
backdev 352fe2c5cf dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 14:04:54 +07:00
backdev 6d80498402 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 13:54:11 +07:00
backdev bb43b6ef4f dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 13:44:49 +07:00
backdev 6793bbfc5c dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 10:43:07 +07:00
backdev 851528ead8 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-05 10:40:25 +07:00
backdev dad0c9db3b dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 17:24:46 +07:00
backdev 50577b43a2 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 16:59:30 +07:00
backdev 25b4601bfb dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 15:15:42 +07:00
backdev aacd485584 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 14:51:56 +07:00
backdev bc86854596 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 14:37:06 +07:00
backdev 0aa30736d8 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 14:25:40 +07:00
backdev c82d67ab6f dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 13:25:33 +07:00
backdev 83a325a5ac dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 13:22:19 +07:00
backdev b7ef3c86e8 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 12:59:51 +07:00
backdev d3ab48d40c dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 11:34:43 +07:00
backdev b79f2a4969 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 11:23:33 +07:00
backdev b19abf32e9 dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 11:09:52 +07:00
backdev bbc2508a9e dev add method link
Test Workflow / test (push) Has been cancelled
2026-05-04 10:50:42 +07:00
backdev 377a71a28e dev add method link
Test Workflow / test (push) Has been cancelled
2026-04-30 18:49:48 +07:00
backdev e1894168b6 dev add method link
Test Workflow / test (push) Has been cancelled
2026-04-30 18:35:35 +07:00
backdev fa4cb2ed1b dev add method link
Test Workflow / test (push) Has been cancelled
2026-04-30 18:24:19 +07:00
backdev c46c3842aa dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-30 16:04:37 +07:00
backdev d885f3fc4c dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-30 15:51:16 +07:00
backdev fb48ce45a0 dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 18:22:07 +07:00
backdev d9249c4ebc dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 18:14:46 +07:00
backdev 18383b1b62 dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 18:14:15 +07:00
backdev 9686eb453f dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 18:01:47 +07:00
backdev 93da73e90b dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 17:41:41 +07:00
backdev 67204d1c5c dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 17:29:19 +07:00
backdev 9a27b56f05 dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 17:16:34 +07:00
backdev f032caf0a3 dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 16:59:27 +07:00
backdev 0f8017a5a9 dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 15:20:46 +07:00
backdev c75ec6aa39 dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 15:13:19 +07:00
backdev ef35c62a61 dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 15:05:56 +07:00
backdev aa14f0dfbf dev add check similar
Test Workflow / test (push) Has been cancelled
2026-04-29 14:53:45 +07:00
backdev ddaf729e18 dev add violation id like required parameters
Test Workflow / test (push) Has been cancelled
2026-04-29 13:33:48 +07:00
backdev 2ca39eca3a dev add violation id like required parameters
Test Workflow / test (push) Has been cancelled
2026-04-29 11:55:18 +07:00
backdev 136b2b2082 dev add violation id like required parameters
Test Workflow / test (push) Has been cancelled
2026-04-29 11:42:11 +07:00
backdev fb091496de dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 17:40:37 +07:00
backdev 5c8431195b dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 17:11:51 +07:00
backdev e5d4ec2f07 dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 16:37:00 +07:00
backdev a87567e45d dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 16:32:30 +07:00
backdev 63e065373f dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 16:09:34 +07:00
backdev c44c251790 dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 15:58:35 +07:00
backdev 61e47975ff dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 15:41:57 +07:00
backdev 7adb52d86f dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 15:13:46 +07:00
backdev e8bcca6ee0 dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 15:07:12 +07:00
backdev 99f4db1d76 dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 14:58:47 +07:00
backdev 097a31fd7b dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 14:52:55 +07:00
backdev cca3a58f5a dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 14:42:41 +07:00
backdev 8a1035c6e1 dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 14:25:31 +07:00
backdev 284b402cdc dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 14:15:29 +07:00
backdev 610ab0977d dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 14:03:43 +07:00
backdev 66af0ea285 dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 13:53:51 +07:00
backdev cb01e24d87 dev fix add count
Test Workflow / test (push) Has been cancelled
2026-04-28 13:30:00 +07:00
backdev b67fb403e6 dev fix check file mimetype
Test Workflow / test (push) Has been cancelled
2026-04-28 12:33:51 +07:00
backdev b3d99b0c02 dev add check for change status
Test Workflow / test (push) Has been cancelled
2026-04-28 09:06:38 +07:00
backdev d1b695a65b dev add check for change status
Test Workflow / test (push) Has been cancelled
2026-04-27 17:56:28 +07:00
backdev 67e547e185 dev add check for change status
Test Workflow / test (push) Has been cancelled
2026-04-27 13:57:19 +07:00
backdev ced8768332 dev add check for change status
Test Workflow / test (push) Has been cancelled
2026-04-27 13:56:52 +07:00
backdev 3e90609ae0 dev add check for change status
Test Workflow / test (push) Has been cancelled
2026-04-27 12:44:13 +07:00
backdev dc27e2ccf2 dev add check for change status
Test Workflow / test (push) Has been cancelled
2026-04-27 12:21:26 +07:00
backdev 3f0a514660 dev fix sort
Test Workflow / test (push) Has been cancelled
2026-04-24 14:14:04 +07:00
backdev 0797ce20e5 dev fix sort
Test Workflow / test (push) Has been cancelled
2026-04-24 13:36:30 +07:00
backdev ab4151b68b dev fix sort
Test Workflow / test (push) Has been cancelled
2026-04-24 13:24:50 +07:00
backdev 0047cfd4f6 dev fix sort
Test Workflow / test (push) Has been cancelled
2026-04-24 13:11:49 +07:00
backdev cdaa6c7ce2 dev fix sort
Test Workflow / test (push) Has been cancelled
2026-04-24 12:54:48 +07:00
backdev d2d78b5117 dev fix sort
Test Workflow / test (push) Has been cancelled
2026-04-23 18:16:50 +07:00
backdev 3002f4b04c dev fix sort
Test Workflow / test (push) Has been cancelled
2026-04-23 18:05:37 +07:00
backdev a34fb9ffa7 dev fix sort
Test Workflow / test (push) Has been cancelled
2026-04-23 16:45:16 +07:00
backdev d0b977291c dev add cold storage
Test Workflow / test (push) Has been cancelled
2026-04-23 14:28:06 +07:00
backdev 71aa8ee01a dev add cold storage
Test Workflow / test (push) Has been cancelled
2026-04-23 14:11:05 +07:00
backdev 04506f4b42 dev add cold storage
Test Workflow / test (push) Has been cancelled
2026-04-23 13:10:24 +07:00
backdev e0ecd91ed0 dev add cold storage
Test Workflow / test (push) Has been cancelled
2026-04-23 12:56:13 +07:00
backdev 2f167a0150 dev add cold storage
Test Workflow / test (push) Has been cancelled
2026-04-23 12:37:14 +07:00
backdev 33c0275a37 dev add cold storage
Test Workflow / test (push) Has been cancelled
2026-04-23 00:38:40 +07:00
backdev d1e36a8dd0 dev merge
Test Workflow / test (push) Has been cancelled
2026-04-22 18:13:20 +07:00
backdev d5f7c73306 dev merge
Test Workflow / test (push) Has been cancelled
2026-04-22 18:05:02 +07:00
backdev 0529af6526 dev merge
Test Workflow / test (push) Has been cancelled
2026-04-22 17:53:36 +07:00
backdev 5de7e828c2 dev merge
Test Workflow / test (push) Has been cancelled
2026-04-22 17:10:25 +07:00
backdev d29258855e dev merge
Test Workflow / test (push) Has been cancelled
2026-04-22 16:24:43 +07:00
backdev cbcd16d376 Merge branch 'NCBACK-35' into dev 2026-04-22 16:03:28 +07:00
backdev eb223c2ecb dev add new action
Test Workflow / test (push) Has been cancelled
2026-04-22 12:38:05 +07:00
backdev bb96e3ac93 dev add new action
Test Workflow / test (push) Has been cancelled
2026-04-22 12:16:37 +07:00
backdev 572255c066 dev add monitoring statistic
Test Workflow / test (push) Has been cancelled
2026-04-20 16:15:08 +07:00
backdev d01ea6e2bd dev fix save to storage
Test Workflow / test (push) Has been cancelled
2026-04-20 15:35:24 +07:00
backdev d1a91fec1a dev add user_id for find all complaints
Test Workflow / test (push) Has been cancelled
2026-04-17 22:00:33 +07:00
151 changed files with 5393 additions and 1698 deletions
+14
View File
@@ -63,6 +63,7 @@ dependencies {
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.12.0' implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.12.0'
implementation 'com.maxmind.geoip2:geoip2:4.2.0' implementation 'com.maxmind.geoip2:geoip2:4.2.0'
implementation 'org.sejda.imageio:webp-imageio:0.1.6'
implementation project(':referral') implementation project(':referral')
@@ -72,6 +73,19 @@ dependencies {
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0")
implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-web")
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.0'
implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.2.0'
//cache
implementation("org.springframework.boot:spring-boot-starter-cache:4.0.6")
implementation 'com.github.ben-manes.caffeine:caffeine'
//security
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation("io.jsonwebtoken:jjwt:0.13.0")
} }
tasks.named('test') { tasks.named('test') {
@@ -2,10 +2,12 @@ package ru.soune.nocopy;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication @SpringBootApplication
@EnableScheduling @EnableScheduling
@EnableCaching
public class NoCopyApplication { public class NoCopyApplication {
public static void main(String[] args) { public static void main(String[] args) {
@@ -1,5 +1,6 @@
package ru.soune.nocopy.configuration; package ru.soune.nocopy.configuration;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.vrt.AudioFilePathProvider; import com.vrt.AudioFilePathProvider;
import com.vrt.fileprotection.FileProtector; import com.vrt.fileprotection.FileProtector;
import com.vrt.fileprotection.audio.AudioLocalSearch; import com.vrt.fileprotection.audio.AudioLocalSearch;
@@ -8,22 +9,23 @@ import com.vrt.fileprotection.image.ImageLocalSearch;
import com.vrt.fileprotection.image.ImageUniqueCheck; import com.vrt.fileprotection.image.ImageUniqueCheck;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.TimeUnit;
@Configuration @Configuration
@EnableAutoConfiguration @EnableAutoConfiguration
@AllArgsConstructor @AllArgsConstructor
@EnableCaching
public class ApplicationConfig { public class ApplicationConfig {
// private final FileEntityRepository fileEntityRepository;
// private final FileUtil fileUtil;
@Bean @Bean
PasswordEncoder passwordEncoder() { PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); return new BCryptPasswordEncoder();
@@ -40,9 +42,6 @@ public class ApplicationConfig {
AudioFilePathProvider audioFilePathProvider, AudioFilePathProvider audioFilePathProvider,
DocumentLocalSearch documentLocalSearch) { DocumentLocalSearch documentLocalSearch) {
// List<FileProtector.FileInfo> initialFiles = loadProcessingFile();
//TODO инициализация файлов при создании
return new com.vrt.NoCopyFileService( return new com.vrt.NoCopyFileService(
Collections.emptyList(), Collections.emptyList(),
fileProvider, fileProvider,
@@ -55,12 +54,20 @@ public class ApplicationConfig {
); );
} }
// private List<FileProtector.FileInfo> loadProcessingFile() { @Bean
// List<FileEntity> byProtectionStatus = public CacheManager cacheManager() {
// fileEntityRepository.findByProtectionStatus(ProtectionStatus.PROCESSING); CaffeineCacheManager cacheManager = new CaffeineCacheManager(
// "reverseImageSearch", "parsedImages");
// return byProtectionStatus.stream().map(fileEntity ->
// fileUtil.createFileInfo(fileEntity, null)).toList(); cacheManager.setCaffeine(Caffeine.newBuilder()
// } .maximumSize(2_000)
.expireAfterWrite(1, TimeUnit.HOURS)
.expireAfterAccess(30, TimeUnit.MINUTES)
.softValues()
.recordStats()
);
return cacheManager;
}
} }
@@ -9,14 +9,33 @@ import java.util.Map;
@Configuration @Configuration
public class HandlerConfig { public class HandlerConfig {
/*
RegRequestHandler
LoginRequestHandler
FileUploadHandler
FileEntityHandler
ImageFoundRequestHandler
VerifyRegisterUserHandler
TariffHandler
ReferralHandler
ResetPasswordHandler
MonitoringHandler
GlobalSearchHandler
ComplaintEntityHandler
ViolationNotionHandler
NotificationHandler
TokenOperationHandler
DockViewFileHandler
*/
/*
Убрать
LogoutRequestHandler logoutHandler
*/
@Bean @Bean
public Map<Integer, RequestHandler> handlers( public Map<Integer, RequestHandler> handlers(
RegRequestHandler reg,
LoginRequestHandler login,
FileUploadHandler upload, FileUploadHandler upload,
FileEntityHandler file, FileEntityHandler file,
LogoutRequestHandler logoutHandler,
ImageFoundRequestHandler imageFoundRequestHandler, ImageFoundRequestHandler imageFoundRequestHandler,
VerifyRegisterUserHandler verifyRegisterUser, VerifyRegisterUserHandler verifyRegisterUser,
AuthRequestHandler authRequestHandler, AuthRequestHandler authRequestHandler,
@@ -24,8 +43,6 @@ public class HandlerConfig {
TariffHandler tariffHandler, TariffHandler tariffHandler,
TariffInfoHandler tariffInfoHandler, TariffInfoHandler tariffInfoHandler,
ReferralHandler referralHandler, ReferralHandler referralHandler,
ResetPasswordHandler resetPasswordHandler,
DaDataHandler daDataHandler,
PaymentHandler paymentHandler, PaymentHandler paymentHandler,
CostHandler costHandler, CostHandler costHandler,
MonitoringHandler monitoringHandler, MonitoringHandler monitoringHandler,
@@ -39,31 +56,19 @@ public class HandlerConfig {
UserVerificationHandler userVerificationHandler, UserVerificationHandler userVerificationHandler,
LawCaseHandler lawCaseHandler, LawCaseHandler lawCaseHandler,
TokenOperationHandler tokenOperationHandler, TokenOperationHandler tokenOperationHandler,
StatisticUserFilesHandler statisticUserHandler, MonitoringStatisticHandler monitoringStatisticHandler,
StatisticTariffInfoFileHandler statisticTariffInfoFileHandler, DockViewFileHandler dockViewFileHandler
StatisticUserDynamicHandler statisticUserDynamicHandler,
StatisticProtectedFilesHandler statisticProtectedFilesHandler,
StatisticViolationHandler statisticViolationHandler,
StatisticSubscriberHandler statisticSubscriberHandler,
StatisticTokenHandler statisticTokenHandler,
StatisticIncomeHandler statisticIncomeHandler
) { ) {
Map<Integer, RequestHandler> map = new HashMap<>(); Map<Integer, RequestHandler> map = new HashMap<>();
map.put(20001, login);
map.put(20002, reg);
map.put(20004, upload); map.put(20004, upload);
map.put(20005, file); map.put(20005, file);
map.put(20006, logoutHandler);
map.put(20007, imageFoundRequestHandler); map.put(20007, imageFoundRequestHandler);
map.put(20008, authRequestHandler); map.put(20008, authRequestHandler);
map.put(20009, verifyRegisterUser); map.put(20009, verifyRegisterUser);
map.put(20010, resetPasswordHandler);
map.put(30000, companyHandler); map.put(30000, companyHandler);
map.put(30001, tariffHandler); map.put(30001, tariffHandler);
map.put(30002, tariffInfoHandler); map.put(30002, tariffInfoHandler);
map.put(30003, referralHandler); map.put(30003, referralHandler);
map.put(30004, daDataHandler);
map.put(30005, paymentHandler); map.put(30005, paymentHandler);
map.put(30007, monitoringHandler); map.put(30007, monitoringHandler);
map.put(30008, costHandler); map.put(30008, costHandler);
@@ -77,6 +82,30 @@ public class HandlerConfig {
map.put(30016, userVerificationHandler); map.put(30016, userVerificationHandler);
map.put(30017, lawCaseHandler); map.put(30017, lawCaseHandler);
map.put(30018, tokenOperationHandler); map.put(30018, tokenOperationHandler);
map.put(30027, monitoringStatisticHandler);
map.put(30028, dockViewFileHandler);
return map;
}
@Bean
public Map<Integer, RequestHandler> internalInfoHandler(
StatisticComplaintHandler statisticComplaintHandler,
StatisticUserFilesHandler statisticUserHandler,
StatisticTariffInfoFileHandler statisticTariffInfoFileHandler,
StatisticUserDynamicHandler statisticUserDynamicHandler,
StatisticProtectedFilesHandler statisticProtectedFilesHandler,
StatisticViolationHandler statisticViolationHandler,
StatisticSubscriberHandler statisticSubscriberHandler,
StatisticTokenHandler statisticTokenHandler,
StatisticIncomeHandler statisticIncomeHandler,
FileInteranlInfoHandler fileInfo,
TariffInformationHandler tariffInformationHandler,
UserInfoHandler userInfoHandler
)
{
Map<Integer, RequestHandler> map = new HashMap<>();
map.put(30014, userInfoHandler);
map.put(30019, statisticUserHandler); map.put(30019, statisticUserHandler);
map.put(30020, statisticTariffInfoFileHandler); map.put(30020, statisticTariffInfoFileHandler);
map.put(30021, statisticUserDynamicHandler); map.put(30021, statisticUserDynamicHandler);
@@ -85,6 +114,43 @@ public class HandlerConfig {
map.put(30024, statisticSubscriberHandler); map.put(30024, statisticSubscriberHandler);
map.put(30025, statisticTokenHandler); map.put(30025, statisticTokenHandler);
map.put(30026, statisticIncomeHandler); map.put(30026, statisticIncomeHandler);
map.put(30029, statisticComplaintHandler);
map.put(40001, fileInfo);
map.put(40004, tariffInformationHandler);
return map;
}
@Bean
public Map<Integer, RequestHandler> internalControlHandler(
ControlComplaintHandler controlComplaintHandler,
FileInternalControlHandler fileInternalControlHandler,
TariffControlHandler tariffControlHandler,
UserInfoHandler userInfoHandler
)
{
Map<Integer, RequestHandler> map = new HashMap<>();
map.put(30014, userInfoHandler);
map.put(30030, controlComplaintHandler);
map.put(40002, fileInternalControlHandler);
map.put(40003, tariffControlHandler);
return map;
}
@Bean
public Map<Integer, RequestHandler> authHandler(
RegRequestHandler reg,
LoginRequestHandler login,
DaDataHandler daDataHandler,
ResetPasswordHandler resetPasswordHandler
)
{
Map<Integer, RequestHandler> map = new HashMap<>();
map.put(20001, login);
map.put(20002, reg);
map.put(30004, daDataHandler);
map.put(20010, resetPasswordHandler);
return map; return map;
} }
@@ -0,0 +1,40 @@
package ru.soune.nocopy.configuration.security;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import ru.soune.nocopy.util.JwtAuthFilter;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthFilter jwtAuthFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("api/v{version}/files/public-download/**").permitAll()
.requestMatchers("/api/files/public/**").permitAll()
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/file/link/**").permitAll()
.requestMatchers("/check/api/**").permitAll()
.requestMatchers("/internal/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
@@ -1,38 +1,33 @@
package ru.soune.nocopy.controller; package ru.soune.nocopy.controller;
import com.google.api.client.util.IOUtils;
import com.google.common.io.ByteStreams;
import com.vrt.NoCopyFileService; import com.vrt.NoCopyFileService;
import com.vrt.fileprotection.FileProtector; import com.vrt.fileprotection.FileProtector;
import com.vrt.fileprotection.NoCopyCheckResult; import com.vrt.fileprotection.NoCopyCheckResult;
import com.vrt.fileprotection.audio.AudioCheckResult; import com.vrt.fileprotection.audio.AudioCheckResult;
import com.vrt.fileprotection.documents.DocumentCheckResult; import com.vrt.fileprotection.documents.DocumentCheckResult;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource; import org.apache.commons.io.IOUtils;
import org.springframework.core.io.InputStreamResource;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault; import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpHeaders; import org.springframework.http.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError; import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import ru.soune.nocopy.dto.BaseRequest; import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.docviewer.DocViewerRequest;
import ru.soune.nocopy.dto.file.*; import ru.soune.nocopy.dto.file.*;
import ru.soune.nocopy.dto.register.RegAnswer; import ru.soune.nocopy.dto.register.RegAnswer;
import ru.soune.nocopy.entity.company.Company; import ru.soune.nocopy.entity.company.Company;
import ru.soune.nocopy.entity.file.FileEntity; import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.file.FileStatus; import ru.soune.nocopy.entity.file.FileStatus;
import ru.soune.nocopy.entity.file.UploadStatus; import ru.soune.nocopy.entity.file.UploadStatus;
import ru.soune.nocopy.entity.file.permission.PermissionType;
import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.*; import ru.soune.nocopy.exception.*;
@@ -41,21 +36,18 @@ import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.repository.FileEntityRepository; import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.repository.UserRepository; import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.FileSimilarityService; import ru.soune.nocopy.service.FileSimilarityService;
import ru.soune.nocopy.service.dockview.DockViewService;
import ru.soune.nocopy.service.file.*; import ru.soune.nocopy.service.file.*;
import ru.soune.nocopy.service.file.CheckCounterService; import ru.soune.nocopy.service.file.CheckCounterService;
import ru.soune.nocopy.service.file.ProtectionsLimitService; import ru.soune.nocopy.service.file.ProtectionsLimitService;
import ru.soune.nocopy.service.file.cloud.CloudStorageService; import ru.soune.nocopy.service.file.cloud.CloudStorageService;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.user.moderation.UserVerificationService;
import ru.soune.nocopy.util.FileUtil;
import software.amazon.awssdk.services.s3.model.NoSuchKeyException; import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files; import java.net.URLEncoder;
import java.nio.file.Path; import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -68,9 +60,13 @@ public class ApiController {
private final Map<Integer, RequestHandler> handlers; private final Map<Integer, RequestHandler> handlers;
private final FileEntityService fileEntityService; private final Map<Integer, RequestHandler> internalInfoHandler;
private final AuthService authService; private final Map<Integer, RequestHandler> internalControlHandler;
private final Map<Integer, RequestHandler> authHandler;
private final FileEntityService fileEntityService;
private final FileSimilarityService fileSimilarityService; private final FileSimilarityService fileSimilarityService;
@@ -78,7 +74,7 @@ public class ApiController {
private final NoCopyFileService noCopyFileService; private final NoCopyFileService noCopyFileService;
private final FileUtil fileUtil; private final HttpServletRequest httpServletRequest;
private final ProtectionsLimitService protectionsLimitService; private final ProtectionsLimitService protectionsLimitService;
@@ -92,7 +88,7 @@ public class ApiController {
private final ZipService zipService; private final ZipService zipService;
private final UserVerificationService userVerificationService; private final DockViewService dockViewService;
@PostMapping("/v{version}/data") @PostMapping("/v{version}/data")
public ResponseEntity<?> handlePostRequest(@RequestBody BaseRequest request, public ResponseEntity<?> handlePostRequest(@RequestBody BaseRequest request,
@@ -135,6 +131,136 @@ public class ApiController {
} }
} }
@PostMapping("/auth")
public ResponseEntity<?> handlePostRequest(@RequestBody BaseRequest request) {
Integer msgId = request.getMsgId();
BaseResponse response;
try {
RequestHandler handler = authHandler.get(msgId);
if (handler == null) {
response = new BaseResponse(msgId,
MessageCode.MSG_ID_NOT_FOUND.getCode(),
MessageCode.MSG_ID_NOT_FOUND.getDescription(),
new HashMap<>());
} else {
response = handler.handle(request);
}
return ResponseEntity.ok().body(response);
} catch (ValidationException e) {
return createValidationErrorResponse(e.getBindingResult(), e.getMsgId());
} catch (UserNotFoundException e) {
return ResponseEntity.ok().body(new BaseResponse(msgId, MessageCode.USER_NOT_FOUND.getCode(),
MessageCode.USER_NOT_FOUND.getDescription(), new HashMap<>()));
} catch (NotFoundAuthToken e) {
return ResponseEntity.ok().body(new BaseResponse(msgId, MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(), new HashMap<>()));
} catch (NotValidFieldException e) {
throw e;
} catch (Exception e) {
log.error("Handler execution failed for msgId: {}", msgId, e);
BaseResponse errorResponse = new BaseResponse(msgId,
MessageCode.INVALID_JSON_BODY.getCode(),
MessageCode.INVALID_JSON_BODY.getDescription(),
new HashMap<>());
return ResponseEntity.ok().body(errorResponse);
}
}
@PostMapping("/internal/data-info")
public ResponseEntity<?> handleInternalInfoPostRequest(@RequestBody BaseRequest request) {
Integer msgId = request.getMsgId();
BaseResponse response;
RequestHandler internalHandler = internalInfoHandler.get(msgId);
try {
if (internalHandler == null) {
response = new BaseResponse(msgId,
MessageCode.MSG_ID_NOT_FOUND.getCode(),
MessageCode.MSG_ID_NOT_FOUND.getDescription(),
new HashMap<>());
} else {
response = internalHandler.handle(request);
}
return ResponseEntity.ok().body(response);
} catch (Exception e) {
log.error("Handler execution failed for msgId: {}", msgId, e);
BaseResponse errorResponse = new BaseResponse(msgId,
MessageCode.INVALID_JSON_BODY.getCode(),
MessageCode.INVALID_JSON_BODY.getDescription(),
new HashMap<>());
return ResponseEntity.ok().body(errorResponse);
}
}
@GetMapping("/internal/data-download/{fileId}")
public ResponseEntity<byte[]> getPublicFile(@PathVariable String fileId) {
try {
FileEntity fileEntity = fileEntityRepository.findById(fileId)
.orElseThrow(() -> new FileNotFoundException("Not found in DB: " + fileId));
MediaType mediaType = getMediaType(fileEntity);
ContentDisposition contentDisposition = ContentDisposition.inline()
.filename(fileEntity.getOriginalFileName(), StandardCharsets.UTF_8)
.build();
byte[] fileBytes;
try (InputStream inputStream = cloudStorageService.readFileFromStorage(fileEntity.getFilePath())) {
fileBytes = IOUtils.toByteArray(inputStream);
}
return ResponseEntity.ok()
.contentType(mediaType)
.header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString())
.header(HttpHeaders.CACHE_CONTROL, "public, max-age=3600")
.body(fileBytes);
} catch (FileNotFoundException e) {
return ResponseEntity.notFound().build();
} catch (NoSuchKeyException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@PostMapping("/internal/data-control")
public ResponseEntity<?> handleInternalControlPostRequest(@RequestBody BaseRequest request) {
Integer msgId = request.getMsgId();
BaseResponse response;
RequestHandler internalHandler = internalControlHandler.get(msgId);
try {
if (internalHandler == null) {
response = new BaseResponse(msgId,
MessageCode.MSG_ID_NOT_FOUND.getCode(),
MessageCode.MSG_ID_NOT_FOUND.getDescription(),
new HashMap<>());
} else {
response = internalHandler.handle(request);
}
return ResponseEntity.ok().body(response);
} catch (Exception e) {
log.error("Handler execution failed for msgId: {}", msgId, e);
BaseResponse errorResponse = new BaseResponse(msgId,
MessageCode.INVALID_JSON_BODY.getCode(),
MessageCode.INVALID_JSON_BODY.getDescription(),
new HashMap<>());
return ResponseEntity.ok().body(errorResponse);
}
}
@PostMapping("/v{version}/files/chunk") @PostMapping("/v{version}/files/chunk")
public ResponseEntity<BaseResponse> uploadChunk( public ResponseEntity<BaseResponse> uploadChunk(
@PathVariable("version") int version, @PathVariable("version") int version,
@@ -187,8 +313,7 @@ public class ApiController {
@RequestParam(value = "upload_id", required = false) String uploadId, @RequestParam(value = "upload_id", required = false) String uploadId,
@RequestParam(value = "chunk_number", required = false) Integer chunkNumber, @RequestParam(value = "chunk_number", required = false) Integer chunkNumber,
@RequestParam(value = "chunk", required = false) MultipartFile chunk, @RequestParam(value = "chunk", required = false) MultipartFile chunk,
@RequestParam(value = "last_file", required = false) Boolean last_file, @RequestParam(value = "last_file", required = false) Boolean last_file) {
@RequestParam(value = "token") String token) {
try { try {
if (chunk == null || chunk.isEmpty()) { if (chunk == null || chunk.isEmpty()) {
return buildErrorResponse(uploadId, chunkNumber, "Chunk file null or empty"); return buildErrorResponse(uploadId, chunkNumber, "Chunk file null or empty");
@@ -200,7 +325,7 @@ public class ApiController {
return buildErrorResponse(uploadId, chunkNumber, "Valid chunk number is required"); return buildErrorResponse(uploadId, chunkNumber, "Valid chunk number is required");
} }
Long userId = authService.useUserAuthToken(token); Long userId = (Long) httpServletRequest.getAttribute("userId");
UploadProgressResponse uploadProgressResponse = fileUploadService.uploadPassportChunk(uploadId, chunkNumber, UploadProgressResponse uploadProgressResponse = fileUploadService.uploadPassportChunk(uploadId, chunkNumber,
chunk, userId); chunk, userId);
@@ -236,7 +361,6 @@ public class ApiController {
public ResponseEntity<BaseResponse> findSimilarFiles( public ResponseEntity<BaseResponse> findSimilarFiles(
@PathVariable("version") int version, @PathVariable("version") int version,
@PathVariable String fileId, @PathVariable String fileId,
@RequestParam(value = "auth_token", required = false) String authToken,
@RequestParam(required = false) List<String> similarityLevels, @RequestParam(required = false) List<String> similarityLevels,
@PageableDefault(size = 20, sort = "hammingDistance") Pageable pageable) { @PageableDefault(size = 20, sort = "hammingDistance") Pageable pageable) {
@@ -248,20 +372,21 @@ public class ApiController {
MessageCode.INVALID_FIELD.getDescription(), null)); MessageCode.INVALID_FIELD.getDescription(), null));
} }
Long userId = (Long) httpServletRequest.getAttribute("userId");
BaseResponse response; BaseResponse response;
if ("image".equals(fileEntity.getMimeType())) { if ("image".equals(fileEntity.getMimeType())) {
Page<SimilarFileDTO> similarFilesPage = fileSimilarityService.findSimilarFiles( Page<SimilarFileDTO> similarFilesPage = fileSimilarityService.findSimilarFiles(
fileId, similarityLevels, pageable, authToken); fileId, similarityLevels, pageable, userId);
response = buildSuccessResponse(similarFilesPage, MessageCode.SIMILAR_FILES_FOUND); response = buildSuccessResponse(similarFilesPage, MessageCode.SIMILAR_FILES_FOUND);
} else { } else {
List<SimilarFileDTO> results = processNonImageFile(fileEntity, authToken); List<SimilarFileDTO> results = processNonImageFile(fileEntity, true);
log.info("results: {}", results); log.info("results: {}", results);
response = buildSuccessResponse(results, MessageCode.SIMILAR_FILES_FOUND); response = buildSuccessResponse(results, MessageCode.SIMILAR_FILES_FOUND);
checkCounterService.incrementCheckCount(fileEntity.getUserId(), fileEntity.getMimeType()); checkCounterService.incrementCheckCount(fileEntity.getUserId(), fileEntity.getMimeType());
} }
return ResponseEntity.ok(response); return ResponseEntity.ok(response);
} catch(IllegalArgumentException e) { } catch(IllegalArgumentException e) {
log.error("Error with file extensions : {}", e.getMessage(), e); log.error("Error with file extensions : {}", e.getMessage(), e);
return ResponseEntity.ok().body(new BaseResponse(MessageCode.FILE_FOR_SEARCH_NOT_VALID.getCode(), return ResponseEntity.ok().body(new BaseResponse(MessageCode.FILE_FOR_SEARCH_NOT_VALID.getCode(),
@@ -275,45 +400,55 @@ public class ApiController {
} }
} }
private List<SimilarFileDTO> processNonImageFile(FileEntity fileEntity, String authToken) throws Exception { private List<SimilarFileDTO> processNonImageFile(FileEntity fileEntity, boolean cloud) throws Exception {
List<SimilarFileDTO> results = new ArrayList<>(); List<SimilarFileDTO> results = new ArrayList<>();
File file = null;
FileEntity duplicateByHash = fileSimilarityService.findDuplicateByHash(fileEntity.getFilePath(), FileEntity duplicateByHash = fileSimilarityService.findDuplicateByHash(fileEntity.getFilePath(),
fileEntity.getMimeType(), fileEntity.getUserId()); fileEntity.getMimeType(), fileEntity.getUserId(), cloud);
log.info("duplicateByHash: {}", duplicateByHash); log.info("duplicateByHash: {}", duplicateByHash);
if (duplicateByHash != null) { if (duplicateByHash != null) {
results.add(fileSimilarityService.buildDTO(duplicateByHash)); results.add(fileSimilarityService.buildDTO(duplicateByHash));
return results; return results;
} }
File file = new File(fileEntity.getFilePath()); try {
FileProtector.Type type = "document".equals(fileEntity.getMimeType()) ? file = cloudStorageService.readFileFromStorageByPath(fileEntity.getFilePath());
FileProtector.Type.DOC : FileProtector.Type.AUDIO; FileProtector.Type type = "document".equals(fileEntity.getMimeType()) ?
FileProtector.Type.DOC : FileProtector.Type.AUDIO;
NoCopyCheckResult checkResult = noCopyFileService.checkFile(file, type); NoCopyCheckResult checkResult = noCopyFileService.checkFile(file, type);
log.info("checkResult: {}", checkResult); log.info("checkResult: {}", checkResult);
switch (checkResult) { switch (checkResult) {
case DocumentCheckResult.Success success -> { case DocumentCheckResult.Success success -> {
FileProtector.FileInfo info = success.getInfo(); FileProtector.FileInfo info = success.getInfo();
FileEntity entity = fileEntityRepository.findByFileId(info.getId()); FileEntity entity = fileEntityRepository.findByFileId(info.getId());
if (entity != null) { if (entity != null) {
results.add(fileSimilarityService.buildDTO(entity)); results.add(fileSimilarityService.buildDTO(entity));
}
} }
} case AudioCheckResult.Success success -> {
case AudioCheckResult.Success success -> { FileProtector.FileInfo info = success.getInfo();
FileProtector.FileInfo info = success.getInfo(); FileEntity entity = fileEntityRepository.findByFileId(info.getId());
FileEntity entity = fileEntityRepository.findByFileId(info.getId()); if (entity != null) {
if (entity != null) { results.add(fileSimilarityService.buildDTO(entity));
results.add(fileSimilarityService.buildDTO(entity)); }
} }
case DocumentCheckResult.Failed failed ->
log.warn("Document check failed: {}", failed.getMessage());
case AudioCheckResult.Failed failed ->
log.warn("Audio check failed: {}", failed.getMessage());
default -> log.warn("Unexpected result type: {}", checkResult.getClass().getSimpleName());
}
} catch (Exception e) {
throw new Exception("Files for search not valid");
} finally {
if (file != null && file.exists()) {
file.delete();
} }
case DocumentCheckResult.Failed failed ->
log.warn("Document check failed: {}", failed.getMessage());
case AudioCheckResult.Failed failed ->
log.warn("Audio check failed: {}", failed.getMessage());
default -> log.warn("Unexpected result type: {}", checkResult.getClass().getSimpleName());
} }
return results; return results;
@@ -438,6 +573,42 @@ public class ApiController {
} }
} }
@GetMapping("/v{version}/files/public-download/{fileId}")
public ResponseEntity<?> downloadFile(
@PathVariable(required = false) String fileId, @PathVariable(required = false) Integer version) {
FileEntityResponse entityResponse = fileEntityService.getById(fileId, version);
FileStatus status = entityResponse.getStatus();
if (status.equals(FileStatus.BLOCKED) || status.equals(FileStatus.DELETED) ||
status.equals(FileStatus.REMOVED)) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("fileId", entityResponse.getId());
return ResponseEntity.ok().body(new BaseResponse(20004,
MessageCode.FILE_IS_BLOCKED.getCode(),
MessageCode.FILE_IS_BLOCKED.getDescription(),
errorData));
}
if (!entityResponse.getPermissions().get(PermissionType.DOWNLOAD)) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("fileId", entityResponse.getId());
return ResponseEntity.ok().body(new BaseResponse(20004,
MessageCode.NOT_HAVE_DOWNLOAD_PERMISSION.getCode(),
MessageCode.NOT_HAVE_DOWNLOAD_PERMISSION.getDescription(),
errorData));
}
byte[] bytes = cloudStorageService.readFileFromStorageBytes(entityResponse.getProtectedFilePath());
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + entityResponse.getFileName() + "\"")
.body(bytes);
}
@GetMapping("/v{version}/files/download/{fileId}") @GetMapping("/v{version}/files/download/{fileId}")
public ResponseEntity<?> downloadFile( public ResponseEntity<?> downloadFile(
@PathVariable(required = false) String fileId, @PathVariable(required = false) String fileId,
@@ -454,7 +625,7 @@ public class ApiController {
errorData)); errorData));
} }
Long userId = authService.useUserAuthToken(tokenHeader); Long userId = (Long) httpServletRequest.getAttribute("userId");
FileEntityResponse entityResponse = fileEntityService.getById(fileId, version); FileEntityResponse entityResponse = fileEntityService.getById(fileId, version);
FileStatus status = entityResponse.getStatus(); FileStatus status = entityResponse.getStatus();
@@ -469,6 +640,16 @@ public class ApiController {
errorData)); errorData));
} }
if (!entityResponse.getPermissions().get(PermissionType.DOWNLOAD)) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("fileId", entityResponse.getId());
return ResponseEntity.ok().body(new BaseResponse(20004,
MessageCode.NOT_HAVE_DOWNLOAD_PERMISSION.getCode(),
MessageCode.NOT_HAVE_DOWNLOAD_PERMISSION.getDescription(),
errorData));
}
User fileUser = userRepository.findById(entityResponse.getUserId()).orElseThrow(); User fileUser = userRepository.findById(entityResponse.getUserId()).orElseThrow();
User user = userRepository.findById(userId).orElseThrow(); User user = userRepository.findById(userId).orElseThrow();
Company companyUser = user.getCompany(); Company companyUser = user.getCompany();
@@ -502,27 +683,6 @@ public class ApiController {
MessageCode.FILE_DELETE.getDescription(), MessageCode.FILE_DELETE.getDescription(),
errorData)); errorData));
} }
//TODO
// if (!entityResponse.isExistsOnDisk()) {
// Map<String, Object> errorData = new HashMap<>();
// errorData.put("onDisk", entityResponse.isExistsOnDisk());
//
// return ResponseEntity.ok().body(new BaseResponse(20004,
// MessageCode.FILE_NOT_EXIST.getCode(),
// MessageCode.FILE_NOT_EXIST.getDescription(),
// errorData));
// }
// if (!file.exists()) {
// Map<String, Object> errorData = new HashMap<>();
// errorData.put("file", file.exists());
//
// return ResponseEntity.ok().body(new BaseResponse(20004,
// MessageCode.FILE_DOWNLOAD_ERROR.getCode(),
// MessageCode.FILE_DOWNLOAD_ERROR.getDescription(),
// errorData));
// }
byte[] bytes = cloudStorageService.readFileFromStorageBytes(entityResponse.getProtectedFilePath()); byte[] bytes = cloudStorageService.readFileFromStorageBytes(entityResponse.getProtectedFilePath());
@@ -547,28 +707,75 @@ public class ApiController {
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(), MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(), MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
errorData)); errorData));
// } catch (IOException e) { }
// Map<String, Object> errorData = new HashMap<>(); }
// errorData.put("token", tokenHeader);
// errorData.put("fileId", fileId); @PostMapping("/file/link")
// errorData.put("version", version); public ResponseEntity<?> downloadFile(@RequestBody DocViewerRequest viewerRequest) {
// try {
// return ResponseEntity.ok().body(new BaseResponse(20004, Long userId = httpServletRequest.getAttribute("userId") == null ? 0L:
// MessageCode.FILE_DOWNLOAD_ERROR_NOT_CORRECT_FIELD.getCode(), (Long) httpServletRequest.getAttribute("userId");
// MessageCode.FILE_DOWNLOAD_ERROR_NOT_CORRECT_FIELD.getDescription(),
// errorData)); if (viewerRequest.getFileId() == null) {
return ResponseEntity.ok().body(new BaseResponse(0,
MessageCode.NOT_VALID_FIELD.getCode(),
MessageCode.NOT_VALID_FIELD.getDescription(),
"file_id is required"));
}
FileEntityResponse entityResponse = fileEntityService.getById(viewerRequest.getFileId(), 0);
FileStatus status = entityResponse.getStatus();
if (status.equals(FileStatus.BLOCKED) || status.equals(FileStatus.DELETED) ||
status.equals(FileStatus.REMOVED)) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("fileId", entityResponse.getId());
return ResponseEntity.ok().body(new BaseResponse(0,
MessageCode.FILE_IS_BLOCKED.getCode(),
MessageCode.FILE_IS_BLOCKED.getDescription(),
errorData));
}
byte[] bytes = cloudStorageService.readFileFromStorageBytes(entityResponse.getProtectedFilePath());
dockViewService.createDockView(viewerRequest, userId);
String filename = entityResponse.getFileName();
String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8)
.replace("+", "%20");
String safeFilename = filename.replaceAll("[^\\x00-\\x7F]", "_");
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + safeFilename + "\"; filename*=UTF-8''" + encodedFilename)
.body(bytes);
} catch (FileEntityNotFoundException e) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("fileId", viewerRequest.getFileId());
return ResponseEntity.ok().body(new BaseResponse(0,
MessageCode.FILE_NOT_FOUND.getCode(),
MessageCode.FILE_NOT_FOUND.getDescription(),
errorData));
} catch (NotFoundAuthToken e) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("token", viewerRequest.getFileId());
return ResponseEntity.ok().body(new BaseResponse(0,
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
errorData));
} }
} }
@GetMapping("/check/file_stats") @GetMapping("/check/file_stats")
public ResponseEntity<?> checkFileProtectStats(@RequestHeader("Authorization") String tokenHeader) { public ResponseEntity<?> checkFileProtectStats() {
String token = tokenHeader.replace("Bearer ", ""); Long userId = (Long) httpServletRequest.getAttribute("userId");
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); Map<String, Object> fileTypeStats = protectionsLimitService.getFileTypeStats(userId);
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found"));
Map<String, Object> fileTypeStats = protectionsLimitService.getFileTypeStats(authToken.getUser().getId());
return ResponseEntity.ok().body(fileTypeStats); return ResponseEntity.ok().body(fileTypeStats);
} }
@@ -629,4 +836,23 @@ public class ApiController {
return errorDetail; return errorDetail;
} }
private MediaType getMediaType(FileEntity fileEntity) {
try {
return MediaType.parseMediaType(fileEntity.getMimeType());
} catch (InvalidMediaTypeException e) {
String extension = fileEntity.getFileExtension().toLowerCase();
switch (extension) {
case "jpg":
case "jpeg":
return MediaType.IMAGE_JPEG;
case "png":
return MediaType.IMAGE_PNG;
case "pdf":
return MediaType.APPLICATION_PDF;
default:
return MediaType.APPLICATION_OCTET_STREAM;
}
}
}
} }
@@ -1,6 +1,5 @@
package ru.soune.nocopy.controller; package ru.soune.nocopy.controller;
import com.google.api.client.util.IOUtils;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.vrt.NoCopyFileService; import com.vrt.NoCopyFileService;
import com.vrt.fileprotection.FileProtector; import com.vrt.fileprotection.FileProtector;
@@ -19,8 +18,6 @@ import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.repository.FileEntityRepository; import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.repository.UserRepository; import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.file.CheckCounterService; import ru.soune.nocopy.service.file.CheckCounterService;
import ru.soune.nocopy.service.file.FileStorageService;
import ru.soune.nocopy.service.file.ImageResizeService;
import ru.soune.nocopy.service.file.ZipService; import ru.soune.nocopy.service.file.ZipService;
import ru.soune.nocopy.service.file.cloud.CloudStorageService; import ru.soune.nocopy.service.file.cloud.CloudStorageService;
import ru.soune.nocopy.util.FileUtil; import ru.soune.nocopy.util.FileUtil;
@@ -30,26 +27,18 @@ import java.io.*;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController @RestController
@RequestMapping("/api/files") @RequestMapping("/api/files")
@Slf4j @Slf4j
@AllArgsConstructor @AllArgsConstructor
public class FileController { public class FileController {
private FileStorageService fileStorageService;
private FileEntityRepository fileRepository; private FileEntityRepository fileRepository;
private CheckCounterService checkCounterService; private CheckCounterService checkCounterService;
private UserRepository userRepository; private UserRepository userRepository;
private ImageResizeService imageResizeService;
private NoCopyFileService noCopyFileService; private NoCopyFileService noCopyFileService;
private FileUtil fileUtil; private FileUtil fileUtil;
@@ -1,19 +1,20 @@
package ru.soune.nocopy.controller; package ru.soune.nocopy.controller;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import ru.soune.nocopy.dto.search.GlobalSearchStartRequest; import ru.soune.nocopy.dto.search.GlobalSearchStartRequest;
import ru.soune.nocopy.dto.search.GlobalSearchStartResponse; import ru.soune.nocopy.dto.search.GlobalSearchStartResponse;
import ru.soune.nocopy.dto.search.GlobalSearchStatusResponse; import ru.soune.nocopy.dto.search.GlobalSearchStatusResponse;
import ru.soune.nocopy.dto.violation.FileViolationSummaryDTO; import ru.soune.nocopy.dto.violation.FileViolationSummaryDTO;
import ru.soune.nocopy.dto.violation.ViolationRequest;
import ru.soune.nocopy.entity.file.FileEntity; import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.search.GlobalSearchTask; import ru.soune.nocopy.entity.search.GlobalSearchTask;
import ru.soune.nocopy.entity.search.SearchStatus; import ru.soune.nocopy.entity.search.SearchStatus;
import ru.soune.nocopy.exception.NotFoundAuthToken;
import ru.soune.nocopy.repository.GlobalSearchTaskRepository; import ru.soune.nocopy.repository.GlobalSearchTaskRepository;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.search.GlobalSearchService; import ru.soune.nocopy.service.search.GlobalSearchService;
import ru.soune.nocopy.service.violation.ViolationService; import ru.soune.nocopy.service.violation.ViolationService;
@@ -25,148 +26,90 @@ import java.util.*;
@RequiredArgsConstructor @RequiredArgsConstructor
public class GlobalSearchController { public class GlobalSearchController {
private final AuthService authService;
private final GlobalSearchService globalSearchService; private final GlobalSearchService globalSearchService;
private final GlobalSearchTaskRepository globalSearchTaskRepository;
private final GlobalSearchTaskRepository searchTaskRepository; private final GlobalSearchTaskRepository searchTaskRepository;
private final ViolationService violationService; private final ViolationService violationService;
private final HttpServletRequest httpServletRequest;
@PostMapping("/start") @PostMapping("/start")
public ResponseEntity<?> startSearch( public ResponseEntity<?> startSearch(
@RequestBody GlobalSearchStartRequest request, @RequestBody GlobalSearchStartRequest request) {
@RequestHeader(value = "Authorization", required = false) String tokenHeader) {
if (tokenHeader == null || tokenHeader.isBlank()) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("token", tokenHeader);
return ResponseEntity.ok().body(Map.of("error", errorData));
}
GlobalSearchStartResponse response = new GlobalSearchStartResponse(); GlobalSearchStartResponse response = new GlobalSearchStartResponse();
try { Long userId = (Long) httpServletRequest.getAttribute("userId");
Long userId = authService.useUserAuthToken(tokenHeader);
List<FileEntity> filesToProcess = globalSearchService.getFilesToProcess(request, userId); List<FileEntity> filesToProcess = globalSearchService.getFilesToProcess(request, userId);
if (filesToProcess.isEmpty()) return ResponseEntity.ok().body("Files for search not found"); if (filesToProcess.isEmpty()) return ResponseEntity.ok().body("Files for search not found");
String taskId = globalSearchService.startSearch(request, userId, filesToProcess); String taskId = globalSearchService.startSearch(request, userId, filesToProcess);
Optional<GlobalSearchTask> taskOptional = globalSearchTaskRepository.findById(taskId); response.setTaskId(taskId);
response.setStatus(SearchStatus.ACCEPTED.name());
if (taskOptional.isEmpty()) return ResponseEntity.ok().body("Task not found"); response.setTotalFiles(filesToProcess.size());
GlobalSearchTask task = taskOptional.orElseThrow();
response.setTaskId(taskId);
response.setStatus(SearchStatus.ACCEPTED.name());
response.setTotalFiles(task.getTotalFiles());
} catch (NotFoundAuthToken e) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("token", tokenHeader);
return ResponseEntity.ok().body(Map.of("error", errorData));
}
return ResponseEntity.ok(response); return ResponseEntity.ok(response);
} }
@GetMapping("/actual-task") @GetMapping("/actual-task")
public ResponseEntity<?> getStatus(@RequestHeader(value = "Authorization", required = false) String tokenHeader) { public ResponseEntity<?> getStatus() {
if (tokenHeader == null || tokenHeader.isBlank()) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("token", tokenHeader);
return ResponseEntity.ok().body(Map.of("error", errorData));
}
Optional<GlobalSearchTask> taskOptional; Optional<GlobalSearchTask> taskOptional;
try { Long userId = (Long) httpServletRequest.getAttribute("userId");
Long userId = authService.useUserAuthToken(tokenHeader);
taskOptional = searchTaskRepository.findByUserIdAndStatus(userId, taskOptional = searchTaskRepository.findByUserIdAndStatus(userId,
"PROCESSING"); "PROCESSING");
if (taskOptional.isEmpty()) return ResponseEntity.ok().body("Task not found"); if (taskOptional.isEmpty()) return ResponseEntity.ok().body("Task not found");
} catch (NotFoundAuthToken e) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("token", tokenHeader);
return ResponseEntity.ok().body(Map.of("error", errorData));
}
return ResponseEntity.ok(taskOptional.get()); return ResponseEntity.ok(taskOptional.get());
} }
@GetMapping("/violation-summary") @GetMapping("/violation-summary")
public ResponseEntity<?> getSummary(@RequestHeader(value = "Authorization", required = false) String tokenHeader) { public ResponseEntity<?> getSummary() {
if (tokenHeader == null || tokenHeader.isBlank()) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("token", tokenHeader);
return ResponseEntity.ok().body(Map.of("error", errorData));
}
List<FileViolationSummaryDTO> fileViolationsSummary; List<FileViolationSummaryDTO> fileViolationsSummary;
try { Long userId = (Long) httpServletRequest.getAttribute("userId");
Long userId = authService.useUserAuthToken(tokenHeader);
fileViolationsSummary = fileViolationsSummary = violationService.getFileViolationsSummary(userId);
violationService.getFileViolationsSummary(userId);
if (fileViolationsSummary.isEmpty()) return ResponseEntity.ok().body("Violations summary not found"); if (fileViolationsSummary.isEmpty()) return ResponseEntity.ok().body("Violations summary not found");
} catch (NotFoundAuthToken e) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("token", tokenHeader);
return ResponseEntity.ok().body(Map.of("error", errorData));
}
return ResponseEntity.ok(fileViolationsSummary); return ResponseEntity.ok(fileViolationsSummary);
} }
@PostMapping("/violation-summary-with-files")
public ResponseEntity<?> getViolations(@RequestBody ViolationRequest request) {
Long userId = (Long) httpServletRequest.getAttribute("userId");
Page<FileViolationSummaryDTO> result = violationService.getFileViolationsSummary(
userId, request.getFileName(), request.getSortDirection(),
request.getPage(), request.getSize(), request.getStartDate(), request.getEndDate());
return ResponseEntity.ok(result);
}
@GetMapping("/status/{taskId}") @GetMapping("/status/{taskId}")
public ResponseEntity<?> getStatus(@PathVariable String taskId, public ResponseEntity<?> getStatus(@PathVariable String taskId) {
@RequestHeader(value = "Authorization", required = false) String tokenHeader) {
if (tokenHeader == null || tokenHeader.isBlank()) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("token", tokenHeader);
return ResponseEntity.ok().body(Map.of("error", errorData));
}
GlobalSearchStatusResponse response; GlobalSearchStatusResponse response;
Long userId = (Long) httpServletRequest.getAttribute("userId");
try { Optional<GlobalSearchTask> taskOptional = searchTaskRepository.findByTaskIdAndUserId(taskId, userId);
Long userId = authService.useUserAuthToken(tokenHeader);
Optional<GlobalSearchTask> taskOptional = searchTaskRepository.findByTaskIdAndUserId(taskId, userId); if (taskOptional.isEmpty()) return ResponseEntity.ok().body("Task not found");
if (taskOptional.isEmpty()) return ResponseEntity.ok().body("Task not found"); GlobalSearchTask task = taskOptional.orElseThrow();
GlobalSearchTask task = taskOptional.orElseThrow(); int progress = task.getTotalFiles() > 0 ? task.getProcessedFiles() * 100 / task.getTotalFiles() : 0;
int progress = task.getTotalFiles() > 0 ? task.getProcessedFiles() * 100 / task.getTotalFiles() : 0; response = new GlobalSearchStatusResponse();
response.setTaskId(taskId);
response.setStatus(task.getStatus());
response.setProgress(progress);
response = new GlobalSearchStatusResponse();
response.setTaskId(taskId);
response.setStatus(task.getStatus());
response.setProgress(progress);
} catch (NotFoundAuthToken e) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("token", tokenHeader);
return ResponseEntity.ok().body(Map.of("error", errorData));
}
return ResponseEntity.ok(response); return ResponseEntity.ok(response);
} }
@@ -0,0 +1,83 @@
package ru.soune.nocopy.controller;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.soune.nocopy.dto.docviewer.DockViewResponse;
import ru.soune.nocopy.entity.docviewer.DockView;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.migration.S3MigrationTool;
import ru.soune.nocopy.repository.DockViewRepository;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.geo.GeoCountryService;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@RestController
@RequestMapping("/api/admin/migration")
@RequiredArgsConstructor
@Slf4j
public class MigrationController {
private final S3MigrationTool migrationTool;
private final DockViewRepository dockViewRepository;
private final GeoCountryService geoCountryService;
private final UserRepository userRepository;
private final FileEntityRepository fileEntityRepository;
@PostMapping("/start")
public ResponseEntity<String> startMigration() {
log.info("Migration triggered via API");
CompletableFuture.runAsync(() -> {
try {
migrationTool.migrationFilesToS3();
} catch (Exception e) {
log.error("Migration failed", e);
}
});
return ResponseEntity.ok("Migration started. Check logs for progress.");
}
@PostMapping("/status")
public ResponseEntity<String> getStatus() {
return ResponseEntity.ok("Check application logs and migration_failed.txt for details");
}
@PostMapping("/fill-dock-view")
public ResponseEntity<String> fillDockView() {
List<DockView> dockViews = dockViewRepository.findAll();
for (DockView dockView: dockViews) {
String viewerIp = dockView.getViewerIp();
Long viewerId = dockView.getViewerId();
String geoEnName = geoCountryService.getCityByIp(viewerIp, "en") + "/" +
geoCountryService.getCountryByIp(viewerIp, "en");
String geoRuName = geoCountryService.getCityByIp(viewerIp, "ru") + "/" +
geoCountryService.getCountryByIp(viewerIp, "ru");
User user = userRepository.findById(viewerId).orElse(null);
FileEntity file = fileEntityRepository.findByFileId(dockView.getFileId());
dockView.setGeoNameRu(geoRuName);
dockView.setGeoNameEn(geoEnName);
dockView.setViewerName(user == null ? "guest" : user.getFullName());
dockView.setDocName(file.getOriginalFileName());
dockViewRepository.save(dockView);
}
return ResponseEntity.ok("fill old dock view");
}
}
@@ -1,17 +1,16 @@
package ru.soune.nocopy.controller; package ru.soune.nocopy.controller;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import ru.soune.nocopy.dto.search.GlobalSearchStartResponse;
import ru.soune.nocopy.entity.payment.Payment; import ru.soune.nocopy.entity.payment.Payment;
import ru.soune.nocopy.exception.PaymentNotFoundException; import ru.soune.nocopy.exception.PaymentNotFoundException;
import ru.soune.nocopy.exception.TariffNotFoundException; import ru.soune.nocopy.exception.TariffNotFoundException;
import ru.soune.nocopy.exception.UserNotFoundException; import ru.soune.nocopy.exception.UserNotFoundException;
import ru.soune.nocopy.service.payment.PaymentService; import ru.soune.nocopy.service.payment.PaymentService;
import ru.soune.nocopy.service.register.AuthService;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -24,7 +23,7 @@ public class PaymentController {
private final PaymentService paymentService; private final PaymentService paymentService;
private final AuthService authService; private final HttpServletRequest httpServletRequest;
@PostMapping("/create") @PostMapping("/create")
public ResponseEntity<?> createPayment(@RequestParam String email, @RequestParam Long tariffId, public ResponseEntity<?> createPayment(@RequestParam String email, @RequestParam Long tariffId,
@@ -69,7 +68,9 @@ public class PaymentController {
return ResponseEntity.ok().body(Map.of("error", errorData)); return ResponseEntity.ok().body(Map.of("error", errorData));
} }
paymentService.changeAutoRenewal(authService.useUserAuthToken(tokenHeader), renewal); Long userId = (Long) httpServletRequest.getAttribute("userId");
paymentService.changeAutoRenewal(userId, renewal);
return ResponseEntity.ok(Map.of("message", "Auto-renewal changed:" + renewal)); return ResponseEntity.ok(Map.of("message", "Auto-renewal changed:" + renewal));
} catch (UserNotFoundException e) { } catch (UserNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND) return ResponseEntity.status(HttpStatus.NOT_FOUND)
@@ -88,7 +89,9 @@ public class PaymentController {
return ResponseEntity.ok().body(Map.of("error", errorData)); return ResponseEntity.ok().body(Map.of("error", errorData));
} }
paymentService.deletePaymentMethod(authService.useUserAuthToken(tokenHeader), paymentMethodId); Long userId = (Long) httpServletRequest.getAttribute("userId");
paymentService.deletePaymentMethod(userId, paymentMethodId);
return ResponseEntity.ok(Map.of("message", "Payment method deleted")); return ResponseEntity.ok(Map.of("message", "Payment method deleted"));
} catch (UserNotFoundException e) { } catch (UserNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND) return ResponseEntity.status(HttpStatus.NOT_FOUND)
@@ -109,8 +112,9 @@ public class PaymentController {
return ResponseEntity.ok().body(Map.of("error", errorData)); return ResponseEntity.ok().body(Map.of("error", errorData));
} }
return ResponseEntity.ok(paymentService.getUserPaymentMethods( Long userId = (Long) httpServletRequest.getAttribute("userId");
authService.useUserAuthToken(tokenHeader)));
return ResponseEntity.ok(paymentService.getUserPaymentMethods(userId));
} catch (UserNotFoundException e) { } catch (UserNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND) return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(Map.of("error", e.getMessage())); .body(Map.of("error", e.getMessage()));
@@ -1,6 +1,7 @@
package ru.soune.nocopy.controller; package ru.soune.nocopy.controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -12,20 +13,16 @@ import ru.soune.nocopy.entity.payout.BankTransferPayoutMethod;
import ru.soune.nocopy.entity.payout.CardPayoutMethod; import ru.soune.nocopy.entity.payout.CardPayoutMethod;
import ru.soune.nocopy.entity.payout.PayoutRequest; import ru.soune.nocopy.entity.payout.PayoutRequest;
import ru.soune.nocopy.entity.payout.PayoutType; import ru.soune.nocopy.entity.payout.PayoutType;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.InsufficientFundsException; import ru.soune.nocopy.exception.InsufficientFundsException;
import ru.soune.nocopy.exception.InvalidPayoutMethodException; import ru.soune.nocopy.exception.InvalidPayoutMethodException;
import ru.soune.nocopy.exception.NotFoundAuthToken;
import ru.soune.nocopy.exception.PendingPayoutExistsException; import ru.soune.nocopy.exception.PendingPayoutExistsException;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.service.payout.PayoutMethodService; import ru.soune.nocopy.service.payout.PayoutMethodService;
import ru.soune.nocopy.service.payout.PayoutRequestService; import ru.soune.nocopy.service.payout.PayoutRequestService;
import ru.soune.nocopy.service.user.UserService;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RestController @RestController
@@ -38,21 +35,21 @@ public class PayoutController {
private final PayoutMethodService payoutMethodService; private final PayoutMethodService payoutMethodService;
private final AuthTokenRepository authTokenRepository; private final HttpServletRequest httpServletRequest;
private final UserService userService;
/* /*
Create payout Create payout
*/ */
@PostMapping("/create-request") @PostMapping("/create-request")
public ResponseEntity<?> createPayoutRequest(@RequestHeader("Authorization") String tokenHeader, public ResponseEntity<?> createPayoutRequest(@Valid @RequestBody PayoutRequestDTO request) {
@Valid @RequestBody PayoutRequestDTO request) { Long userId = (Long) httpServletRequest.getAttribute("userId");
String token = tokenHeader.replace("Bearer ", ""); User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found with id: " + userId);
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
try { try {
PayoutRequest payoutRequest = payoutRequestService.createPayoutRequest(user.getId(), request); PayoutRequest payoutRequest = payoutRequestService.createPayoutRequest(user.getId(), request);
@@ -76,15 +73,13 @@ public class PayoutController {
Cancel payout Cancel payout
*/ */
@PostMapping("/requests/{requestId}/cancel") @PostMapping("/requests/{requestId}/cancel")
public ResponseEntity<PayoutRequest> cancelPayoutRequest(@PathVariable Long requestId, public ResponseEntity<PayoutRequest> cancelPayoutRequest(@PathVariable Long requestId) {
@RequestHeader("Authorization") String tokenHeader) { Long userId = (Long) httpServletRequest.getAttribute("userId");
String token = tokenHeader.replace("Bearer ", ""); User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
return ResponseEntity.notFound().build();
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
PayoutRequest cancelled = payoutRequestService.cancelPayoutRequest(user.getId(), requestId); PayoutRequest cancelled = payoutRequestService.cancelPayoutRequest(user.getId(), requestId);
@@ -95,14 +90,13 @@ public class PayoutController {
Get user payouts Get user payouts
*/ */
@GetMapping("/requests") @GetMapping("/requests")
public ResponseEntity<List<PayoutRequest>> getUserRequests(@RequestHeader("Authorization") String tokenHeader) { public ResponseEntity<List<PayoutRequest>> getUserRequests() {
String token = tokenHeader.replace("Bearer ", ""); Long userId = (Long) httpServletRequest.getAttribute("userId");
User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
return ResponseEntity.notFound().build();
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
return ResponseEntity.ok(payoutRequestService.getUserPayoutRequests(user.getId())); return ResponseEntity.ok(payoutRequestService.getUserPayoutRequests(user.getId()));
} }
@@ -111,15 +105,13 @@ public class PayoutController {
Get payout by id Get payout by id
*/ */
@GetMapping("/requests/{requestId}") @GetMapping("/requests/{requestId}")
public ResponseEntity<PayoutRequest> getPayoutRequest(@PathVariable Long requestId, public ResponseEntity<PayoutRequest> getPayoutRequest(@PathVariable Long requestId) {
@RequestHeader("Authorization") String tokenHeader) { Long userId = (Long) httpServletRequest.getAttribute("userId");
String token = tokenHeader.replace("Bearer ", ""); User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
return ResponseEntity.notFound().build();
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
return ResponseEntity.ok(payoutRequestService.getPayoutRequest(user.getId(), requestId)); return ResponseEntity.ok(payoutRequestService.getPayoutRequest(user.getId(), requestId));
} }
@@ -128,14 +120,13 @@ public class PayoutController {
Get payout by id Get payout by id
*/ */
@GetMapping("user/payout-methods") @GetMapping("user/payout-methods")
public ResponseEntity<List<PayoutMethodDTO>> getUserMethods(@RequestHeader("Authorization") String tokenHeader) { public ResponseEntity<List<PayoutMethodDTO>> getUserMethods() {
String token = tokenHeader.replace("Bearer ", ""); Long userId = (Long) httpServletRequest.getAttribute("userId");
User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
return ResponseEntity.notFound().build();
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
return ResponseEntity.ok(payoutMethodService.getUserMethods(user.getId())); return ResponseEntity.ok(payoutMethodService.getUserMethods(user.getId()));
} }
@@ -158,15 +149,13 @@ public class PayoutController {
add card method by userId add card method by userId
*/ */
@PostMapping("/payout-method/card") @PostMapping("/payout-method/card")
public ResponseEntity<PayoutMethodDTO> addCardMethod(@Valid @RequestBody AddCardRequest request, public ResponseEntity<PayoutMethodDTO> addCardMethod(@Valid @RequestBody AddCardRequest request) {
@RequestHeader("Authorization") String tokenHeader) { Long userId = (Long) httpServletRequest.getAttribute("userId");
String token = tokenHeader.replace("Bearer ", ""); User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
return ResponseEntity.notFound().build();
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
CardPayoutMethod method = payoutMethodService.addCardMethod(user.getId(), request); CardPayoutMethod method = payoutMethodService.addCardMethod(user.getId(), request);
@@ -178,15 +167,13 @@ public class PayoutController {
add bank payout-method add bank payout-method
*/ */
@PostMapping("/payout-method/bank-transfer") @PostMapping("/payout-method/bank-transfer")
public ResponseEntity<PayoutMethodDTO> addBankTransferMethod(@Valid @RequestBody AddBankTransferRequest request, public ResponseEntity<PayoutMethodDTO> addBankTransferMethod(@Valid @RequestBody AddBankTransferRequest request) {
@RequestHeader("Authorization") String tokenHeader) { Long userId = (Long) httpServletRequest.getAttribute("userId");
String token = tokenHeader.replace("Bearer ", ""); User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
return ResponseEntity.notFound().build();
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
BankTransferPayoutMethod method = payoutMethodService.addBankTransferMethod(user.getId(), request); BankTransferPayoutMethod method = payoutMethodService.addBankTransferMethod(user.getId(), request);
@@ -199,15 +186,13 @@ public class PayoutController {
set default bank payout-method set default bank payout-method
*/ */
@PutMapping("/payout-method/{methodId}/default") @PutMapping("/payout-method/{methodId}/default")
public ResponseEntity<Void> setDefaultMethod(@PathVariable Long methodId, public ResponseEntity<Void> setDefaultMethod(@PathVariable Long methodId) {
@RequestHeader("Authorization") String tokenHeader) { Long userId = (Long) httpServletRequest.getAttribute("userId");
String token = tokenHeader.replace("Bearer ", ""); User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
return ResponseEntity.notFound().build();
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
payoutMethodService.setDefaultMethod(user.getId(), methodId); payoutMethodService.setDefaultMethod(user.getId(), methodId);
@@ -1,5 +1,6 @@
package ru.soune.nocopy.controller; package ru.soune.nocopy.controller;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@@ -14,23 +15,19 @@ import ru.soune.nocopy.dto.user.UserDTO;
import ru.soune.nocopy.dto.user.UserRequest; import ru.soune.nocopy.dto.user.UserRequest;
import ru.soune.nocopy.entity.tarif.Tariff; import ru.soune.nocopy.entity.tarif.Tariff;
import ru.soune.nocopy.entity.tarif.TariffInfo; import ru.soune.nocopy.entity.tarif.TariffInfo;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.InvalidUserEmail; import ru.soune.nocopy.exception.InvalidUserEmail;
import ru.soune.nocopy.exception.NotFoundAuthToken;
import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.exception.UserNotFoundException;
import ru.soune.nocopy.mapper.UserMapper; import ru.soune.nocopy.mapper.UserMapper;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.repository.UserRepository; import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.file.FileStatsService; import ru.soune.nocopy.service.file.FileStatsService;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.tariff.TariffService; import ru.soune.nocopy.service.tariff.TariffService;
import ru.soune.nocopy.service.user.UserService; import ru.soune.nocopy.service.user.UserService;
import ru.soune.nocopy.util.JwtUtil;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
@RestController @RestController
@RequestMapping("v1/api/user") @RequestMapping("v1/api/user")
@@ -41,101 +38,79 @@ public class UserController {
private final UserService userService; private final UserService userService;
private final AuthTokenRepository authTokenRepository;
private final UserMapper userMapper; private final UserMapper userMapper;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final AuthService authService;
private final TariffService tariffService; private final TariffService tariffService;
private final FileStatsService fileStatsService; private final FileStatsService fileStatsService;
@GetMapping("/all") private final JwtUtil jwtUtil;
public ResponseEntity<List<UserDTO>> getAllUsers() {
List<UserDTO> allUsers = userRepository.findAll().stream() private final HttpServletRequest httpServletRequest;
.map(u -> new UserDTO(u.getFullName(), u.getCompanyName(), u.getEmail(), u.isActive(),
u.getPhone(), u.getGenderType(),
u.getBirthday(), u.getCreatedAt(), u.getSubscriptionType(), tariffService.getAllTariffs(),
null, null, u.getVerificationStatus()))
.toList();
return ResponseEntity.ok(allUsers);
}
@GetMapping @GetMapping
public ResponseEntity<UserDTO> getUser(@RequestParam("email") String email, public ResponseEntity<UserDTO> getUser(@RequestParam("email") String email) {
@RequestHeader("Authorization") String tokenHeader) { User user = userRepository.findByEmail(email);
String token = tokenHeader.replace("Bearer ", "");
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user != null) {
UserDTO userDTO = userMapper.toDTO(user);
userDTO.setEmail(email);
userDTO.setFullName(user.getFullName());
userDTO.setVerifiedStatus(user.getVerificationStatus());
if (tokenOptional.isPresent()) { if (user.getCompany() != null) {
User user = userRepository.findByEmail(email); userDTO.setCompany(user.getCompany().getCompanyName());
if (user != null) {
UserDTO userDTO = userMapper.toDTO(user);
userDTO.setEmail(email);
userDTO.setFullName(user.getFullName());
userDTO.setVerifiedStatus(user.getVerificationStatus());
if (user.getCompany() != null) {
userDTO.setCompany(user.getCompany().getCompanyName());
}
if (user.canManageCompanySettings() || user.canLogin() && user.getCompany() == null) {
userDTO.setTariffs(tariffService.getTariffByAccountType(user));
Long fileOnDisk = user.canManageCompanySettings() ?
fileStatsService.calculateCompanyFileSize(user.getId()):
fileStatsService.calculateUserFileSize(user.getId());
Integer filesCount = user.canManageCompanySettings() ?
fileStatsService.filesCompanyCount(user.getId()):
fileStatsService.filesUserCount(user.getId());
TariffInfo personalTariffInfo;
if (user.getCompany() == null) {
personalTariffInfo = user.getPersonalTariffInfo();
} else {
personalTariffInfo = user.getCompany().getTariffInfo();
}
Tariff tariff = personalTariffInfo.getTariff();
TariffInfoDTO infoDTO = TariffInfoDTO.builder().tokens(personalTariffInfo.getTokens())
.id(personalTariffInfo.getId())
.tariffName(tariff.getName())
.status(personalTariffInfo.getStatus().name())
.tariffId(tariff.getId())
.currentFileCounts(filesCount)
.maxFileCounts(tariff.getMaxFilesCount())
.currentFileOnDisk(fileOnDisk)
.maxFileOnDisk(tariff.getDiskSize())
.startTariff(personalTariffInfo.getStartTariff())
.endTariff(personalTariffInfo.getEndTariff())
.tokens(personalTariffInfo.getTokens() + personalTariffInfo.getBoughtTokens())
.build();
userDTO.setTariffInfo(infoDTO);
}
userDTO.setPhone(user.getPhone());
userDTO.setGenderType(user.getGenderType());
userDTO.setBirthday(user.getBirthday());
userDTO.setCreatedAt(user.getCreatedAt());
userDTO.setSubscriptionType(user.getSubscriptionType());
userDTO.setActive(user.isActive());
userDTO.setPermission(user.getUserPermissions());
return ResponseEntity.ok(userDTO);
} }
} else {
return ResponseEntity.notFound().build(); if (user.canManageCompanySettings() || user.canLogin() && user.getCompany() == null) {
userDTO.setTariffs(tariffService.getTariffByAccountType(user));
Long fileOnDisk = user.canManageCompanySettings() ?
fileStatsService.calculateCompanyFileSize(user.getId()):
fileStatsService.calculateUserFileSize(user.getId());
Integer filesCount = user.canManageCompanySettings() ?
fileStatsService.filesCompanyCount(user.getId()):
fileStatsService.filesUserCount(user.getId());
TariffInfo personalTariffInfo;
if (user.getCompany() == null) {
personalTariffInfo = user.getPersonalTariffInfo();
} else {
personalTariffInfo = user.getCompany().getTariffInfo();
}
Tariff tariff = personalTariffInfo.getTariff();
TariffInfoDTO infoDTO = TariffInfoDTO.builder().tokens(personalTariffInfo.getTokens())
.id(personalTariffInfo.getId())
.tariffName(tariff.getName())
.status(personalTariffInfo.getStatus().name())
.tariffId(tariff.getId())
.currentFileCounts(filesCount)
.maxFileCounts(tariff.getMaxFilesCount())
.currentFileOnDisk(fileOnDisk)
.maxFileOnDisk(tariff.getDiskSize())
.startTariff(personalTariffInfo.getStartTariff())
.endTariff(personalTariffInfo.getEndTariff())
.tokens(personalTariffInfo.getTokens() + personalTariffInfo.getBoughtTokens())
.build();
userDTO.setTariffInfo(infoDTO);
}
userDTO.setPhone(user.getPhone());
userDTO.setGenderType(user.getGenderType());
userDTO.setBirthday(user.getBirthday());
userDTO.setCreatedAt(user.getCreatedAt());
userDTO.setActive(user.isActive());
userDTO.setPermission(user.getUserPermissions());
return ResponseEntity.ok(userDTO);
} }
return ResponseEntity.notFound().build(); return ResponseEntity.notFound().build();
@@ -143,15 +118,13 @@ public class UserController {
//TODO fix mapper,doesnot exist all fields //TODO fix mapper,doesnot exist all fields
@PostMapping("/change-password") @PostMapping("/change-password")
public ResponseEntity<UserDTO> updateUser(@RequestBody ChangePasswordRequest changePasswordRequest, public ResponseEntity<UserDTO> updateUser(@RequestBody ChangePasswordRequest changePasswordRequest) {
@RequestHeader("Authorization") String tokenHeader) { Long userId = (Long) httpServletRequest.getAttribute("userId");
String token = tokenHeader.replace("Bearer ", ""); User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
throw new UserNotFoundException("User not found by id: " + userId);
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
if (!changePasswordRequest.getEmail().equals(user.getEmail())) { if (!changePasswordRequest.getEmail().equals(user.getEmail())) {
throw new InvalidUserEmail("Email is not valid: " + changePasswordRequest.getEmail() + "not found"); throw new InvalidUserEmail("Email is not valid: " + changePasswordRequest.getEmail() + "not found");
@@ -163,21 +136,19 @@ public class UserController {
} }
@PatchMapping("/user-update") @PatchMapping("/user-update")
public ResponseEntity<UserDTO> updateUser(@RequestBody UserRequest userRequest, public ResponseEntity<UserDTO> updateUser(@RequestBody UserRequest userRequest) {
@RequestHeader("Authorization") String tokenHeader) { Long userId = (Long) httpServletRequest.getAttribute("userId");
String token = tokenHeader.replace("Bearer ", ""); User user = userService.getUserById(userId).orElse(null);
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token); if (user == null) {
throw new UserNotFoundException("User not found by id: " + userId);
AuthToken authToken = tokenOptional.orElseThrow(() -> new NotFoundAuthToken("Token: " + token + "not found")); }
User user = authToken.getUser();
return ResponseEntity.ok(userService.updateUser(userRequest, user)); return ResponseEntity.ok(userService.updateUser(userRequest, user));
} }
@PostMapping("/create-user") @PostMapping("/create-user")
public ResponseEntity<User> addUser(@RequestBody RegRequest registerRequest) { public ResponseEntity<?> addUser(@RequestBody RegRequest registerRequest) {
if (userRepository.existsByEmail(registerRequest.getEmail()) || if (userRepository.existsByEmail(registerRequest.getEmail()) ||
userRepository.existsByPhone(registerRequest.getPhone())) { userRepository.existsByPhone(registerRequest.getPhone())) {
@@ -204,11 +175,11 @@ public class UserController {
User savedUser = userRepository.save(user); User savedUser = userRepository.save(user);
AuthToken authToken = authService.generateAuthToken(savedUser); String authToken = jwtUtil.generateToken(savedUser.getId(), savedUser.getEmail());
authTokenRepository.save(authToken); return ResponseEntity.ok().body(Map.of(
"user", savedUser,
return ResponseEntity.ok().body(savedUser); "token", authToken));
} }
@DeleteMapping("/delete-user/{userId}") @DeleteMapping("/delete-user/{userId}")
@@ -15,4 +15,7 @@ public class BaseRequest {
@JsonProperty("message_body") @JsonProperty("message_body")
Object messageBody; Object messageBody;
@JsonProperty(value = "admin_id", required = false)
Long adminId;
} }
@@ -18,10 +18,15 @@ public enum MessageCode {
FILE_NOT_EXIST(2, "File not exist on disk"), FILE_NOT_EXIST(2, "File not exist on disk"),
FILE_DELETE(2, "File was deleted"), FILE_DELETE(2, "File was deleted"),
USER_NOT_HAD_PERMISSION(2, "User not have permission for file"), USER_NOT_HAD_PERMISSION(2, "User not have permission for file"),
NOT_OWNER_FILE_STATUS_VIOLATION(2, "Violation in not owner file status"),
USER_NOT_VERIFIED(2, "User not verified"), USER_NOT_VERIFIED(2, "User not verified"),
LAW_CASE_NOT_FOUND(4, "Law case not found"), LAW_CASE_NOT_FOUND(4, "Law case not found"),
PERMISSION_NOT_FOUND(2, "Permission not found"), PERMISSION_NOT_FOUND(2, "Permission not found"),
INVALID_CREDENTIALS(2, "Invalid credentials"),
USER_NOT_FOUND(2, "User not found"), USER_NOT_FOUND(2, "User not found"),
LAW_CASE_ALREADY_EXIST(2, "Law case already exists"),
COMPLAINT_ALREADY_EXIST(2, "Complaint already exists"),
COMPLAINT_NOT_FOUND(4, "Complaint not found"),
FILE_DOWNLOAD_ERROR_NOT_CORRECT_FIELD(2, "Not correct field"), FILE_DOWNLOAD_ERROR_NOT_CORRECT_FIELD(2, "Not correct field"),
TOKEN_IS_NULL(2, "Token field is null"), TOKEN_IS_NULL(2, "Token field is null"),
IMAGE_FOUND_ERROR(2, "Image found error"), IMAGE_FOUND_ERROR(2, "Image found error"),
@@ -32,7 +37,7 @@ public enum MessageCode {
FILE_ENTITY_ERROR(2, "File entity error"), FILE_ENTITY_ERROR(2, "File entity error"),
NOT_VALID_FIELD(2, "Not valid field"), NOT_VALID_FIELD(2, "Not valid field"),
ACCESS_DENIED(2, "Access denied"), ACCESS_DENIED(2, "Access denied"),
AUTH_EMAIL_NOT_FOUND(4, "Email not found"), AUTH_EMAIL_NOT_FOUND(4, "Email not COMPLAINT_OR_LAW_CASE_IN_WORK"),
AUTH_EMAIL_OR_TOKEN_NOT_FOUND(4, "Email or Token not found "), AUTH_EMAIL_OR_TOKEN_NOT_FOUND(4, "Email or Token not found "),
AUTH_TOKEN_MISMATCH(4, "Token mismatch"), AUTH_TOKEN_MISMATCH(4, "Token mismatch"),
AUTH_TOKEN_NOT_FOUND(4, "Token not found"), AUTH_TOKEN_NOT_FOUND(4, "Token not found"),
@@ -44,6 +49,7 @@ public enum MessageCode {
FILE_IS_NOT_PROTECTED(0, "File is not protected"), FILE_IS_NOT_PROTECTED(0, "File is not protected"),
TARIFF_IS_ADD(0, "Tariff is added"), TARIFF_IS_ADD(0, "Tariff is added"),
TARIFF_IS_DELETED(0, "Tariff is deleted"), TARIFF_IS_DELETED(0, "Tariff is deleted"),
TARIFF_IS_NOT_DELETED(0, "Tariff is not deleted,use some users"),
TARIFF_IS_UPDATED(0, "Tariff is updated"), TARIFF_IS_UPDATED(0, "Tariff is updated"),
TARIFF_IS_NOT_FOUND(0, "Tariff is not found"), TARIFF_IS_NOT_FOUND(0, "Tariff is not found"),
VALIDATION_ERROR(2, "Validation error"), VALIDATION_ERROR(2, "Validation error"),
@@ -65,8 +71,13 @@ public enum MessageCode {
NOT_FOUND(4, "Notion not found"), NOT_FOUND(4, "Notion not found"),
MESSAGE_IS_REQUIRED_FOR_NOTION(4, "Message is required for notion"), MESSAGE_IS_REQUIRED_FOR_NOTION(4, "Message is required for notion"),
USER_VERIFICATIONS_NOT_FOUND(4, "Verifications not found"), USER_VERIFICATIONS_NOT_FOUND(4, "Verifications not found"),
COMPLAINT_OR_LAW_CASE_IN_WORK(2, "Complaint or lawcase in work"),
NOT_VALID_STATUS(2, "Not valid status"),
PERMISSION_NOT_VALID(2, "Not valid permission"),
NOT_HAVE_DOWNLOAD_PERMISSION(2, "Not haver permission for download"),
ADMIN_USER_NOT_FOUND(4, "Verifications ,user or admin not found"); ADMIN_USER_NOT_FOUND(4, "Verifications ,user or admin not found");
private final Integer code; private final Integer code;
private final String description; private final String description;
@@ -6,6 +6,4 @@ import lombok.Data;
@Data @Data
public class TokenProcessRequest { public class TokenProcessRequest {
@JsonProperty("token")
private String token;
} }
@@ -36,4 +36,7 @@ public class ComplaintResponse {
@JsonProperty("not_moderated") @JsonProperty("not_moderated")
private Boolean notModerated; private Boolean notModerated;
@JsonProperty("file_id")
private String fileId;
} }
@@ -18,15 +18,14 @@ public class LawCaseRequest {
private String priority = LawCasePriority.HIGH.toString(); private String priority = LawCasePriority.HIGH.toString();
private String type; private String type;
private String lawyer; private String lawyer;
private String token;
private Integer pageSize = 5; private Integer pageSize = 5;
private Integer pageNumber = 0; private Integer pageNumber = 0;
private String sortBy = "updatedAt"; private String sortBy = "updatedAt";
private String sortDir = "desc"; private String sortDir = "desc";
private String action; private String action;
private LawCaseType filterType; private String filterType;
private String filterLawyer; private String filterLawyer;
private LawCasePriority filterPriority; private String filterPriority;
@JsonProperty("violation_id") @JsonProperty("violation_id")
private Long violationId; private Long violationId;
@@ -1,5 +1,6 @@
package ru.soune.nocopy.dto.complaint; package ru.soune.nocopy.dto.complaint;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import ru.soune.nocopy.entity.complaint.LawCase; import ru.soune.nocopy.entity.complaint.LawCase;
@@ -14,19 +15,43 @@ import java.util.List;
@Builder @Builder
public class LawCaseResponse { public class LawCaseResponse {
private Long id; private Long id;
private String name; private String name;
private String description; private String description;
private BigDecimal amount; private BigDecimal amount;
private LawCasePriority priority; private LawCasePriority priority;
private LawCaseType type; private LawCaseType type;
private String lawyer; private String lawyer;
@JsonProperty("created_at")
private LocalDateTime createdAt; private LocalDateTime createdAt;
@JsonProperty("updated_at")
private LocalDateTime updatedAt; private LocalDateTime updatedAt;
@JsonProperty("page_number")
private int pageNumber; private int pageNumber;
@JsonProperty("page_size")
private int pageSize; private int pageSize;
@JsonProperty("total_elements")
private long totalElements; private long totalElements;
@JsonProperty("total_pages")
private int totalPages; private int totalPages;
@JsonProperty("violation_id")
private long violationId; private long violationId;
@JsonProperty("file_id")
private String fileId;
private List<LawCaseResponse> content; private List<LawCaseResponse> content;
public static LawCaseResponse fromEntity(LawCase lawCase) { public static LawCaseResponse fromEntity(LawCase lawCase) {
@@ -12,7 +12,4 @@ public class CostRequest {
@JsonProperty("count_files") @JsonProperty("count_files")
Integer countFilesForProtect; Integer countFilesForProtect;
@JsonProperty("auth_token")
String authToken;
} }
@@ -0,0 +1,36 @@
package ru.soune.nocopy.dto.docviewer;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class DocViewerRequest {
@JsonProperty("file_id")
private String fileId;
@JsonProperty("ip")
private String ip;
@JsonProperty("user_agent")
private String userAgent;
@JsonProperty("page")
private int page = 0;
@JsonProperty("size")
private int size = 10;
@JsonProperty("sort_by")
private String sortBy = "createdAt";
@JsonProperty("sort_direction")
private String sortDirection = "desc";
@JsonProperty("action")
private String action;
@JsonProperty("locale")
private String locale;
}
@@ -0,0 +1,31 @@
package ru.soune.nocopy.dto.docviewer;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DockViewResponse {
@JsonProperty("city")
private String city;
@JsonProperty("country")
private String country;
@JsonProperty("viewer")
private String viewer;
@JsonProperty("document")
private String document;
@JsonProperty("view_date")
private LocalDateTime viewDate;
}
@@ -0,0 +1,55 @@
package ru.soune.nocopy.dto.docviewer;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DockViewStatsResponse {
private String fileId;
private Long totalViews;
private Long uniqueIps;
private Long uniqueUsers;
private int documentsCount;
private int uniqueCountryCount;
private int uniqueCityCount;
private LocalDateTime firstViewDate;
private LocalDateTime lastViewDate;
private List<DockViewStatsResponse> content;
private List<DockViewResponse> history;
private Integer pageNumber;
private Integer pageSize;
private Long totalElements;
private Integer totalPages;
private Boolean isLast;
private Boolean isFirst;
private Boolean hasNext;
private Boolean hasPrevious;
}
@@ -9,5 +9,4 @@ public class AppealRequest {
private String fileId; private String fileId;
private String appealReason; private String appealReason;
private String additionalInfo; private String additionalInfo;
private String token;
} }
@@ -14,6 +14,7 @@ public class AppealResponse {
private String additionalInfo; private String additionalInfo;
private String status; private String status;
private String adminComment; private String adminComment;
private String fileName;
private LocalDateTime createdAt; private LocalDateTime createdAt;
private LocalDateTime resolvedAt; private LocalDateTime resolvedAt;
} }
@@ -6,6 +6,10 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import ru.soune.nocopy.entity.file.FileStatus; import ru.soune.nocopy.entity.file.FileStatus;
import ru.soune.nocopy.entity.file.permission.PermissionType;
import java.util.List;
import java.util.Map;
@Data @Data
@Builder @Builder
@@ -18,6 +22,9 @@ public class FileEntityRequest {
@JsonProperty("file_id") @JsonProperty("file_id")
private String fileId; private String fileId;
@JsonProperty("file_ids")
private List<String> fileIds;
@JsonProperty("full_delete") @JsonProperty("full_delete")
private Integer fullDelete; private Integer fullDelete;
@@ -33,9 +40,6 @@ public class FileEntityRequest {
@JsonProperty("page_size") @JsonProperty("page_size")
private Integer pageSize; private Integer pageSize;
@JsonProperty("token")
private String token;
@JsonProperty("sort_by") @JsonProperty("sort_by")
private String sortBy; private String sortBy;
@@ -71,4 +75,7 @@ public class FileEntityRequest {
@JsonProperty("search_query") @JsonProperty("search_query")
private String searchQuery; private String searchQuery;
@JsonProperty("permissions")
private Map<String, Boolean> permissions;
} }
@@ -5,8 +5,10 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import ru.soune.nocopy.entity.file.FileStatus; import ru.soune.nocopy.entity.file.FileStatus;
import ru.soune.nocopy.entity.file.permission.PermissionType;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Map;
@Data @Data
@Builder @Builder
@@ -42,4 +44,5 @@ public class FileEntityResponse {
private Integer checksCount; private Integer checksCount;
private LocalDateTime fileUploadDate; private LocalDateTime fileUploadDate;
private String monitoring; private String monitoring;
private Map<PermissionType, Boolean> permissions;
} }
@@ -16,12 +16,6 @@ public class FileListResponse {
@JsonProperty("files") @JsonProperty("files")
private List<FileEntityResponse> files; private List<FileEntityResponse> files;
@JsonProperty("total_count")
private Integer totalCount;
@JsonProperty("total_size")
private Long totalSize;
@JsonProperty("formatted_total_size") @JsonProperty("formatted_total_size")
private String formattedTotalSize; private String formattedTotalSize;
@@ -36,4 +30,10 @@ public class FileListResponse {
@JsonProperty("sort_order") @JsonProperty("sort_order")
private String sortOrder; private String sortOrder;
@JsonProperty("total_count")
private Integer totalCount;
@JsonProperty("total_size")
private Long totalSize;
} }
@@ -26,9 +26,6 @@ public class FileUploadRequest {
@JsonProperty("action") @JsonProperty("action")
private String action; private String action;
@JsonProperty("token")
private String token;
@JsonProperty("convertTo") @JsonProperty("convertTo")
private String convertTo; private String convertTo;
} }
@@ -8,6 +8,9 @@ public class ImageSearchRequest {
@JsonProperty("file_id") @JsonProperty("file_id")
private String fileId; private String fileId;
@JsonProperty("check_similar_first")
private Boolean checkSimilarFirst;
@JsonProperty("page") @JsonProperty("page")
private Integer page = 1; private Integer page = 1;
@@ -10,7 +10,7 @@ public class ModerationActionRequest {
private String fileId; private String fileId;
private FileStatus newStatus; private FileStatus newStatus;
private String comment; private String comment;
private String token; private Long adminId;
} }
@@ -17,7 +17,4 @@ public class GetViolationsRequest {
@JsonProperty("mark_as_read") @JsonProperty("mark_as_read")
private boolean markAsRead; private boolean markAsRead;
@JsonProperty("auth_token")
private String authToken;
} }
@@ -14,7 +14,4 @@ public class SetMonitoringRequest {
@JsonProperty("monitoring_type") @JsonProperty("monitoring_type")
private String monitoringType; private String monitoringType;
@JsonProperty("auth_token")
private String authToken;
} }
@@ -4,5 +4,4 @@ import lombok.Data;
@Data @Data
public class ActivateNotificationRequest { public class ActivateNotificationRequest {
private String authToken;
} }
@@ -7,5 +7,4 @@ import java.util.List;
@Data @Data
public class MarkAsReadRequest { public class MarkAsReadRequest {
private List<Long> notificationIds; private List<Long> notificationIds;
private String authToken;
} }
@@ -15,4 +15,5 @@ public class NotificationDto {
private NotificationType type; private NotificationType type;
private NotificationStatus status; private NotificationStatus status;
private LocalDateTime createdAt; private LocalDateTime createdAt;
private Object context;
} }
@@ -14,5 +14,4 @@ public class NotificationListRequest {
private String sortDirection = "DESC"; private String sortDirection = "DESC";
private List<NotificationType> types; private List<NotificationType> types;
private List<NotificationStatus> statuses; private List<NotificationStatus> statuses;
private String authToken;
} }
@@ -10,7 +10,6 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
@Builder @Builder
public class ReferralRequest { public class ReferralRequest {
private String token;
private Integer amount; private Integer amount;
private Integer pageSize; private Integer pageSize;
private Integer pageNumber; private Integer pageNumber;
@@ -6,9 +6,6 @@ import lombok.Data;
@Data @Data
public class GlobalSearchStatisticsRequest { public class GlobalSearchStatisticsRequest {
@JsonProperty("token")
private String token;
@JsonProperty("limit") @JsonProperty("limit")
private Integer limit = 10; private Integer limit = 10;
@@ -0,0 +1,7 @@
package ru.soune.nocopy.dto.statistic;
import lombok.Data;
@Data
public class ComplaintStatisticRequest {
}
@@ -0,0 +1,34 @@
package ru.soune.nocopy.dto.statistic;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ComplaintStatisticResponse {
@JsonProperty("total_complaint")
private Long totalComplaints;
@JsonProperty("total_created")
private Long totalCreated;
@JsonProperty("total_in_work")
private Long totalInWork;
@JsonProperty("total_completed")
private Long totalCompleted;
@JsonProperty("total_cancelled")
private Long totalCancelled;
@JsonProperty("complaints")
private Map<String, Object> complaints;
}
@@ -0,0 +1,7 @@
package ru.soune.nocopy.dto.statistic;
import lombok.Data;
@Data
public class MonitoringStatisticRequest {
}
@@ -0,0 +1,20 @@
package ru.soune.nocopy.dto.statistic;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class MonitoringStatisticResponse {
@JsonProperty("day")
private Long everyDay;
@JsonProperty("month")
private Long everyMonth;
@JsonProperty("weekly")
private Long everyWeekly;
}
@@ -17,4 +17,5 @@ public class TariffDTO {
private Long diskSize; private Long diskSize;
private Long maxUsers; private Long maxUsers;
private String tariffTerm; private String tariffTerm;
private String description;
} }
@@ -24,25 +24,20 @@ public class TariffRequest {
@JsonProperty("tariff_name") @JsonProperty("tariff_name")
private String name; private String name;
@Min(value = 0, message = "Price cannot be negative")
@JsonProperty("tariff_price") @JsonProperty("tariff_price")
private double price; private Double price;
@Min(value = 0, message = "Tokens must be at least 0")
@JsonProperty("tariff_tokens") @JsonProperty("tariff_tokens")
private int tokens; private Integer tokens;
@Min(value = 0, message = "Max files count must be at least 0")
@JsonProperty("max_files") @JsonProperty("max_files")
private int maxFilesCount; private Integer maxFilesCount;
@Min(value = 0, message = "Disk size must be at least 0")
@JsonProperty("disk_size") @JsonProperty("disk_size")
private int diskSize; private Long diskSize;
@Min(value = 0, message = "Max users must be at least 0")
@JsonProperty("max_users") @JsonProperty("max_users")
private int maxUsers; private Long maxUsers;
@JsonProperty("action") @JsonProperty("action")
private String action; private String action;
@@ -52,4 +47,22 @@ public class TariffRequest {
@JsonProperty("tariff_term") @JsonProperty("tariff_term")
private String tariffTerm; private String tariffTerm;
@JsonProperty("description")
private String description;
@JsonProperty("account_type")
private String accountType;
@JsonProperty("page")
private Integer page;
@JsonProperty("page_size")
private Integer size;
@JsonProperty("sort_by")
private String sortBy;
@JsonProperty("sort_direction")
private String sortDirection = "desc";
} }
@@ -1,12 +1,41 @@
package ru.soune.nocopy.dto.tarriff; package ru.soune.nocopy.dto.tarriff;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import ru.soune.nocopy.entity.tarif.Tariff;
import java.util.List;
@Data @Data
@Builder @Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class TariffResponse { public class TariffResponse {
@JsonProperty("tariff_name")
private String tariffName; private String tariffName;
@JsonProperty("type")
private String tariffType; private String tariffType;
@JsonProperty("page")
private Integer page;
@JsonProperty("page_size")
private Integer pageSize;
@JsonProperty("sort_by")
private String sortBy;
@JsonProperty("sort_direction")
private String sortDirection;
@JsonProperty("total_pages")
private Integer totalPages;
@JsonProperty("total_elements")
private Long totalElements;
@JsonProperty("tariffs")
private List<TariffDTO> tariffs;
} }
@@ -11,9 +11,6 @@ public class TokenOperationRequest {
@JsonProperty("action") @JsonProperty("action")
private String action; private String action;
@JsonProperty("token")
private String token;
@JsonProperty("operation_id") @JsonProperty("operation_id")
private Long operationId; private Long operationId;
@@ -2,6 +2,9 @@ package ru.soune.nocopy.dto.user;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import ru.soune.nocopy.entity.user.SubscriptionType;
import java.time.LocalDate;
@Data @Data
public class UserAdditionalInfoBody { public class UserAdditionalInfoBody {
@@ -17,4 +20,37 @@ public class UserAdditionalInfoBody {
@JsonProperty("user_agent") @JsonProperty("user_agent")
private String userAgent; private String userAgent;
@JsonProperty("page")
private int page = 0;
@JsonProperty("size")
private int size = 5;
@JsonProperty("sort_by")
private String sortBy;
@JsonProperty("sort_direction")
private String sortDirection = "desc";
@JsonProperty("full_name")
private String fullName;
@JsonProperty("email")
private String email;
@JsonProperty("is_active")
private Boolean isActive;
@JsonProperty("email_verified")
private Boolean emailVerified;
@JsonProperty("sub_type")
private SubscriptionType subscriptionType;
@JsonProperty("date_from")
private LocalDate dateFrom;
@JsonProperty("date_to")
private LocalDate dateTo;
} }
@@ -27,7 +27,7 @@ public class UserDTO {
private GenderType genderType; private GenderType genderType;
private LocalDate birthday; private LocalDate birthday;
private LocalDateTime createdAt; private LocalDateTime createdAt;
private SubscriptionType subscriptionType; private String subscriptionType;
private List<TariffDTO> tariffs; private List<TariffDTO> tariffs;
private TariffInfoDTO tariffInfo; private TariffInfoDTO tariffInfo;
private Long permission; private Long permission;
@@ -18,5 +18,7 @@ public class FileViolationSummaryDTO {
private FileStatus status; private FileStatus status;
private LocalDateTime createdAt; private LocalDateTime createdAt;
private long violationCount; private long violationCount;
private long countLawCase;
private long countComplaint;
private LocalDateTime latestViolationDate; private LocalDateTime latestViolationDate;
} }
@@ -1,12 +1,20 @@
package ru.soune.nocopy.dto.violation; package ru.soune.nocopy.dto.violation;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
@Data @Data
public class ViolationNotionRequest { public class ViolationNotionRequest {
private String token;
@JsonProperty("action")
private String action; private String action;
@JsonProperty("violation_id")
private Long violationId; private Long violationId;
@JsonProperty("notion_id")
private Long notionId; private Long notionId;
@JsonProperty("message")
private String message; private String message;
} }
@@ -13,15 +13,6 @@ public class ViolationRequest {
@JsonProperty("violation_id") @JsonProperty("violation_id")
private Long violationId; private Long violationId;
@JsonProperty("page")
private Integer page = 0;
@JsonProperty("size")
private Integer size = 10;
@JsonProperty("sort_direction")
private String sortDirection = "desc";
@JsonProperty("status") @JsonProperty("status")
private String status; private String status;
@@ -31,12 +22,22 @@ public class ViolationRequest {
@JsonProperty("end_date") @JsonProperty("end_date")
private String endDate; private String endDate;
@JsonProperty("group_by")
private String groupBy;
@JsonProperty("action") @JsonProperty("action")
private String action; private String action;
@JsonProperty("token") @JsonProperty("file_name")
private String token; private String fileName = null;
@JsonProperty("page")
private Integer page = 0;
@JsonProperty("size")
private Integer size = 10;
@JsonProperty("sort_direction")
private String sortDirection = "desc";
@JsonProperty("group_by")
private String groupBy;
} }
@@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import ru.soune.nocopy.entity.violation.Violation; import ru.soune.nocopy.entity.violation.Violation;
import ru.soune.nocopy.service.geo.GeoCountryService;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@@ -13,8 +12,6 @@ import java.util.List;
@Builder @Builder
public class ViolationResponse { public class ViolationResponse {
private final GeoCountryService geoCountryService;
@JsonProperty("violations") @JsonProperty("violations")
private List<ViolationDto> violations; private List<ViolationDto> violations;
@@ -6,9 +6,6 @@ import lombok.Data;
@Data @Data
public class ViolationStatisticsRequest { public class ViolationStatisticsRequest {
@JsonProperty("token")
private String token;
@JsonProperty("file_id") @JsonProperty("file_id")
private String fileId; private String fileId;
@@ -14,6 +14,12 @@ public class ViolationStatisticsResponse {
@JsonProperty("new_violations") @JsonProperty("new_violations")
private long newViolations; private long newViolations;
@JsonProperty("total_complaints")
private Long totalComplaints;
@JsonProperty("total_law_cases")
private Long totalLawCases;
@JsonProperty("in_progress_violations") @JsonProperty("in_progress_violations")
private long inProgressViolations; private long inProgressViolations;
@@ -51,7 +51,7 @@ public class Company {
@ToString.Exclude @ToString.Exclude
private List<User> users = new ArrayList<>(); private List<User> users = new ArrayList<>();
@OneToOne(cascade = CascadeType.ALL) @OneToOne(cascade = CascadeType.MERGE)
@JoinColumn(name = "tariff_info_id") @JoinColumn(name = "tariff_info_id")
private TariffInfo tariffInfo; private TariffInfo tariffInfo;
} }
@@ -0,0 +1,48 @@
package ru.soune.nocopy.entity.docviewer;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import java.time.LocalDateTime;
@Table(name = "dock_view")
@RequiredArgsConstructor
@AllArgsConstructor
@Entity
@Setter @Getter
public class DockView {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "viewer_id")
private Long viewerId;
@Column(name = "viewer_ip")
private String viewerIp;
@Column(name = "user_agent")
private String userAgent;
@Column(name = "file_id")
private String fileId;
@Column(name = "geo_name_ru")
private String geoNameRu;
@Column(name = "geo_name_en")
private String geoNameEn;
@Column(name = "viewer_name")
private String viewerName;
@Column(name = "document_name")
private String docName;
@Column(name = "created_at",updatable = false)
private LocalDateTime createdAt = LocalDateTime.now();
}
@@ -6,10 +6,13 @@ import lombok.*;
import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener; import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import ru.soune.nocopy.entity.file.permission.PermissionType;
import ru.soune.nocopy.entity.monitoring.FileMonitoringEntity; import ru.soune.nocopy.entity.monitoring.FileMonitoringEntity;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@Data @Data
@@ -92,6 +95,14 @@ public class FileEntity {
@Column @Column
private String newExtension; private String newExtension;
@ElementCollection
@CollectionTable(name = "file_permissions",
joinColumns = @JoinColumn(name = "file_id"))
@Column(name = "allowed")
@MapKeyEnumerated(EnumType.STRING)
@MapKeyColumn(name = "permission_type")
private Map<PermissionType, Boolean> permissions = new HashMap<>();
@OneToOne(mappedBy = "file", cascade = CascadeType.ALL, orphanRemoval = true) @OneToOne(mappedBy = "file", cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnore @JsonIgnore
private ImageHashEntity imageHash; private ImageHashEntity imageHash;
@@ -113,6 +124,15 @@ public class FileEntity {
if (this.createdAt == null) { if (this.createdAt == null) {
this.createdAt = LocalDateTime.now(); this.createdAt = LocalDateTime.now();
} }
if (this.permissions == null) {
this.permissions = new HashMap<>();
this.permissions.put(PermissionType.DOWNLOAD, true);
// this.permissions.put(PermissionType.VIEW, true);
// this.permissions.put(PermissionType.EDIT, true);
}
this.updatedAt = LocalDateTime.now(); this.updatedAt = LocalDateTime.now();
} }
@@ -124,4 +144,29 @@ public class FileEntity {
public static void initializeCounter(int maxId) { public static void initializeCounter(int maxId) {
supportIdCounter = new AtomicInteger(maxId); supportIdCounter = new AtomicInteger(maxId);
} }
@Transient
public boolean hasPermission(PermissionType type) {
return permissions.getOrDefault(type, false);
}
@Transient
public void setPermission(PermissionType type, boolean allowed) {
permissions.put(type, allowed);
}
@Transient
public boolean canDownload() {
return hasPermission(PermissionType.DOWNLOAD);
}
// @Transient
// public boolean canView() {
// return hasPermission(PermissionType.VIEW);
// }
//
// @Transient
// public boolean canEdit() {
// return hasPermission(PermissionType.EDIT);
// }
} }
@@ -0,0 +1,27 @@
package ru.soune.nocopy.entity.file.permission;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public enum PermissionType {
DOWNLOAD;
public static Set<String> getValidPermissionNames() {
return Arrays.stream(PermissionType.values())
.map(Enum::name)
.collect(Collectors.toSet());
}
public static Set<String> getInvalidPermissions(Map<String, Boolean> permissions) {
Set<String> validNames = getValidPermissionNames();
return permissions.keySet().stream()
.filter(key -> !validNames.contains(key))
.collect(Collectors.toSet());
}
public static boolean areAllValid(Map<String, Boolean> permissions) {
return getInvalidPermissions(permissions).isEmpty();
}
}
@@ -42,6 +42,9 @@ public class Notification {
@Column(name = "status") @Column(name = "status")
private NotificationStatus status = NotificationStatus.NEW; private NotificationStatus status = NotificationStatus.NEW;
@Column(name = "context", columnDefinition = "TEXT")
private String context;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id") @JoinColumn(name = "user_id")
@JsonIgnore @JsonIgnore
@@ -31,4 +31,7 @@ public class GlobalSearchTask {
private LocalDateTime createdAt; private LocalDateTime createdAt;
private LocalDateTime updatedAt; private LocalDateTime updatedAt;
@Version
private Long version;
} }
@@ -41,6 +41,9 @@ public class Tariff {
@Column(name = "tariffAccountType") @Column(name = "tariffAccountType")
private String tariffAccountType; private String tariffAccountType;
@Column(name = "description", columnDefinition = "TEXT")
private String description;
@Column(name = "tariff_term") @Column(name = "tariff_term")
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
private TariffTimeTerm tariffTerm; private TariffTimeTerm tariffTerm;
@@ -49,10 +49,6 @@ public class User {
@Column(unique = true) @Column(unique = true)
private String phone; private String phone;
@Enumerated(EnumType.STRING)
@Column(name = "subscription_type", nullable = false, length = 20)
private SubscriptionType subscriptionType = SubscriptionType.DEMO;
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
@Column(name = "gender") @Column(name = "gender")
private GenderType genderType = GenderType.MALE; private GenderType genderType = GenderType.MALE;
@@ -0,0 +1,7 @@
package ru.soune.nocopy.exception;
public class TaskCancelledException extends RuntimeException {
public TaskCancelledException(String message) {
super(message);
}
}
@@ -1,15 +1,14 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest; import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.TokenProcessRequest;
import ru.soune.nocopy.exception.NotFoundAuthToken; import ru.soune.nocopy.exception.NotFoundAuthToken;
import ru.soune.nocopy.service.register.AuthService; import ru.soune.nocopy.util.JwtUtil;
import java.util.Map; import java.util.Map;
@@ -18,20 +17,19 @@ import java.util.Map;
@RequiredArgsConstructor @RequiredArgsConstructor
public class AuthRequestHandler implements RequestHandler { public class AuthRequestHandler implements RequestHandler {
private final ObjectMapper objectMapper; private final HttpServletRequest httpServletRequest;
private final AuthService authService; private final JwtUtil jwtUtil;
@Override @Override
public BaseResponse handle(BaseRequest request) throws NotFoundAuthToken { public BaseResponse handle(BaseRequest request) throws NotFoundAuthToken {
TokenProcessRequest tokenProcessRequest = objectMapper.convertValue(request.getMessageBody(), Long userId = (Long) httpServletRequest.getAttribute("userId");
TokenProcessRequest.class); String email = (String) httpServletRequest.getAttribute("email");
String token = jwtUtil.generateToken(userId, email);
authService.useUserAuthToken(tokenProcessRequest.getToken());
return new BaseResponse(request.getMsgId(), return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(), MessageCode.SUCCESS.getCode(),
"Token processed successfully", "Token processed successfully",
Map.of("token", tokenProcessRequest.getToken())); Map.of("token", token));
} }
} }
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@@ -12,10 +13,19 @@ import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.complaint.ComplaintRequest; import ru.soune.nocopy.dto.complaint.ComplaintRequest;
import ru.soune.nocopy.dto.complaint.ComplaintResponse; import ru.soune.nocopy.dto.complaint.ComplaintResponse;
import ru.soune.nocopy.entity.complaint.ComplaintEntity;
import ru.soune.nocopy.entity.complaint.ComplaintStatus; import ru.soune.nocopy.entity.complaint.ComplaintStatus;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.entity.violation.Violation;
import ru.soune.nocopy.repository.ComplaintEntityRepository;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.repository.ViolationRepository;
import ru.soune.nocopy.service.complaint.ComplaintEntityService; import ru.soune.nocopy.service.complaint.ComplaintEntityService;
import java.util.HashMap; import ru.soune.nocopy.service.user.UserService;
import java.util.Map; import ru.soune.nocopy.service.violation.ViolationStatus;
import java.util.*;
@Slf4j @Slf4j
@Component @Component
@@ -25,66 +35,111 @@ public class ComplaintEntityHandler implements RequestHandler {
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final UserRepository userRepository;
private final UserService userService;
private final FileEntityRepository fileEntityRepository;
private final ComplaintEntityRepository complaintEntityRepository;
private final ViolationRepository violationRepository;
private final HttpServletRequest httpServletRequest;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
Integer msgId = request.getMsgId(); Integer msgId = request.getMsgId();
ComplaintRequest complaintRequest = objectMapper.convertValue(request.getMessageBody(), ComplaintRequest.class); ComplaintRequest complaintRequest = objectMapper.convertValue(request.getMessageBody(), ComplaintRequest.class);
String action = complaintRequest.getAction(); String action = complaintRequest.getAction() == null ? "" : complaintRequest.getAction();
Long userId = (Long) httpServletRequest.getAttribute("userId");
User user = userRepository.findById(userId).orElse(null);
if (user == null) {
return new BaseResponse(
request.getMsgId(),
MessageCode.USER_NOT_FOUND.getCode(),
MessageCode.USER_NOT_FOUND.getDescription(),
Map.of("userId: ", userId));
}
List<String> emails = user.getCompany() == null ? List.of(user.getEmail()):
userService.getUsersCompanyEmails(user.getCompany().getId());
try { try {
switch (action.toLowerCase()) { return switch (action) {
case "create": case "create" -> handleCreate(msgId, complaintRequest, userId);
return handleCreate(msgId, complaintRequest); case "get" -> handleGet(msgId, complaintRequest, userId);
case "get": case "get_all" -> handleGetAll(msgId, complaintRequest, emails);
return handleGet(msgId, complaintRequest); case "get_by_violation" -> handleGetByViolation(msgId, complaintRequest, userId);
case "get_all": case "update_status" -> handleUpdateStatus(msgId, complaintRequest, userId);
return handleGetAll(msgId, complaintRequest); case "update" -> handleUpdate(msgId, complaintRequest, userId);
case "get_by_violation": case "delete" -> handleDelete(msgId, complaintRequest);
return handleGetByViolation(msgId, complaintRequest); default -> errorResponse(msgId, MessageCode.MSG_ID_NOT_FOUND.getCode(), "Valid actions: " +
case "update_status": List.of("create", "get", "get_all", "get_by_violation", "update_status",
return handleUpdateStatus(msgId, complaintRequest); "update", "delete"));
case "update": };
return handleUpdate(msgId, complaintRequest);
case "delete":
return handleDelete(msgId, complaintRequest);
default:
return errorResponse(msgId, MessageCode.MSG_ID_NOT_FOUND.getCode(), "Unknown action: " + action);
}
} catch (Exception e) { } catch (Exception e) {
log.error("Error handling complaint request", e); log.error("Error handling complaint request", e);
return errorResponse(msgId, MessageCode.INVALID_JSON_BODY.getCode(), e.getMessage()); return errorResponse(msgId, MessageCode.INVALID_JSON_BODY.getCode(), e.getMessage());
} }
} }
private BaseResponse handleCreate(Integer msgId, ComplaintRequest req) { private BaseResponse handleCreate(Integer msgId, ComplaintRequest req, Long userId) {
if (req.getViolationId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), if (req.getViolationId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(),
"violation_id is required"); "violation_id is required");
if (req.getComplaintText() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), if (req.getComplaintText() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(),
"text is required"); "text is required");
Long violationId = req.getViolationId();
Violation violation = violationRepository.findById(violationId).orElse(null);
if (violation == null || !Objects.equals(violation.getFileEntity().getUserId(), userId)) {
return errorResponse(msgId, MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
MessageCode.USER_NOT_HAD_PERMISSION.getDescription());
}
if (violation.getStatus().equals(ViolationStatus.NOT_OWNER_FILE.name())) {
return errorResponse(msgId, MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
MessageCode.USER_NOT_HAD_PERMISSION.getDescription());
}
if (complaintEntityRepository.existsByViolationId(violationId)) {
return errorResponse(msgId, MessageCode.COMPLAINT_ALREADY_EXIST.getCode(),
MessageCode.COMPLAINT_ALREADY_EXIST.getDescription());
}
ComplaintResponse response = complaintService.createComplaint(req); ComplaintResponse response = complaintService.createComplaint(req);
return successResponse(msgId, "Complaint created successfully", response); return successResponse(msgId, "Complaint created successfully", response);
} }
private BaseResponse handleGet(Integer msgId, ComplaintRequest req) { private BaseResponse handleGet(Integer msgId, ComplaintRequest req, Long userId) {
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required"); if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
ComplaintResponse response = complaintService.getComplaintById(req.getId()); ComplaintResponse response = complaintService.getComplaintById(req.getId());
if (!Objects.equals(fileEntityRepository.findByFileId(response.getFileId()).getUserId(), userId)) {
return errorResponse(msgId, MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
"User not have permission for file");
}
return successResponse(msgId, "Complaint retrieved successfully", response); return successResponse(msgId, "Complaint retrieved successfully", response);
} }
private BaseResponse handleGetAll(Integer msgId, ComplaintRequest req) { private BaseResponse handleGetAll(Integer msgId, ComplaintRequest req, List<String> emails) {
Pageable pageable = PageRequest.of( Pageable pageable = PageRequest.of(
req.getPage() != null ? req.getPage() : 0, req.getPage() != null ? req.getPage() : 0,
req.getSize() != null ? req.getSize() : 5, req.getSize() != null ? req.getSize() : 5,
Sort.by(Sort.Direction.fromString(req.getSortDirection() != null ? req.getSortDirection() : "desc"), Sort.by(Sort.Direction.fromString(
req.getSortDirection() != null ? req.getSortDirection() : "desc"),
req.getSortBy() != null ? req.getSortBy() : "updatedAt")); req.getSortBy() != null ? req.getSortBy() : "updatedAt"));
var page = complaintService.getAllComplaints(pageable); var page = complaintService.getAllComplaintsByEmail(pageable, emails);
Map<String, Object> data = new HashMap<>(); Map<String, Object> data = new HashMap<>();
data.put("content", page.getContent()); data.put("content", page.getContent());
data.put("page", page.getNumber()); data.put("page", page.getNumber() + 1);
data.put("size", page.getSize()); data.put("size", page.getSize());
data.put("totalElements", page.getTotalElements()); data.put("totalElements", page.getTotalElements());
data.put("totalPages", page.getTotalPages()); data.put("totalPages", page.getTotalPages());
@@ -92,30 +147,56 @@ public class ComplaintEntityHandler implements RequestHandler {
return successResponse(msgId, "Complaints retrieved successfully", data); return successResponse(msgId, "Complaints retrieved successfully", data);
} }
private BaseResponse handleGetByViolation(Integer msgId, ComplaintRequest req) { private BaseResponse handleGetByViolation(Integer msgId, ComplaintRequest req, Long userId) {
if (req.getViolationId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), if (req.getViolationId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(),
"violation_id is required"); "violation_id is required");
var complaints = complaintService.getComplaintsByViolationId(req.getViolationId()); ComplaintResponse response = complaintService.getComplaintsByViolationId(req.getViolationId());
Map<String, Object> data = new HashMap<>();
data.put("content", complaints);
data.put("totalElements", complaints.size());
return successResponse(msgId, "Complaints retrieved successfully", data); if (!Objects.equals(fileEntityRepository.findByFileId(response.getFileId()).getUserId(), userId)) {
return errorResponse(msgId, MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
"User not have permission for file");
}
return successResponse(msgId, "Complaints retrieved successfully", response);
} }
private BaseResponse handleUpdateStatus(Integer msgId, ComplaintRequest req) { private BaseResponse handleUpdateStatus(Integer msgId, ComplaintRequest req, Long userId) {
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required"); if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
if (req.getStatus() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "status is required"); if (req.getStatus() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "status is required");
List<String> statuses = Arrays.stream(ComplaintStatus.values()).map(ComplaintStatus::name).toList();
if (statuses.stream().noneMatch(status -> status.equals(req.getStatus().toUpperCase()))) {
return errorResponse(msgId, MessageCode.NOT_VALID_STATUS.getCode(), "Valid statuses: " + statuses);
}
ComplaintStatus status = ComplaintStatus.valueOf(req.getStatus().toUpperCase()); ComplaintStatus status = ComplaintStatus.valueOf(req.getStatus().toUpperCase());
ComplaintResponse response = complaintService.updateComplaintStatus(req.getId(), status);
ComplaintEntity complaintEntity = complaintEntityRepository.findById(req.getId()).orElse(null);
if (complaintEntity == null || !Objects.equals(
complaintEntity.getViolation().getFileEntity().getUserId(), userId)) {
return errorResponse(msgId, MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
MessageCode.USER_NOT_HAD_PERMISSION.getDescription());
}
ComplaintResponse response = complaintService.updateComplaintStatus(complaintEntity, status);
return successResponse(msgId, "Status updated successfully", response); return successResponse(msgId, "Status updated successfully", response);
} }
private BaseResponse handleUpdate(Integer msgId, ComplaintRequest req) { private BaseResponse handleUpdate(Integer msgId, ComplaintRequest req, Long userId) {
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required"); if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
ComplaintEntity complaintEntity = complaintEntityRepository.findById(req.getId()).orElse(null);
if (complaintEntity == null || !Objects.equals(
complaintEntity.getViolation().getFileEntity().getUserId(), userId)) {
return errorResponse(msgId, MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
MessageCode.USER_NOT_HAD_PERMISSION.getDescription());
}
ComplaintResponse response = complaintService.updateComplaint(req.getId(), req); ComplaintResponse response = complaintService.updateComplaint(req.getId(), req);
return successResponse(msgId, "Complaint updated successfully", response); return successResponse(msgId, "Complaint updated successfully", response);
@@ -0,0 +1,121 @@
package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.complaint.ComplaintRequest;
import ru.soune.nocopy.dto.complaint.ComplaintResponse;
import ru.soune.nocopy.entity.complaint.ComplaintEntity;
import ru.soune.nocopy.entity.complaint.ComplaintStatus;
import ru.soune.nocopy.repository.ComplaintEntityRepository;
import ru.soune.nocopy.service.complaint.ComplaintEntityService;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@Component
@RequiredArgsConstructor
@Slf4j
public class ControlComplaintHandler implements RequestHandler{
private final ObjectMapper objectMapper;
private final ComplaintEntityRepository complaintEntityRepository;
private final ComplaintEntityService complaintService;
@Override
public BaseResponse handle(BaseRequest request) throws Exception {
ComplaintRequest complaintRequest = objectMapper.convertValue(request.getMessageBody(), ComplaintRequest.class);
Integer msgId = request.getMsgId();
log.info("start create complaint!");
try {
return switch (complaintRequest.getAction()) {
case "update_status" -> updateStatus(msgId, complaintRequest);
case "update" -> update(msgId, complaintRequest);
case "delete" -> delete(msgId, complaintRequest);
case "create" -> create(msgId, complaintRequest);
default -> errorResponse(msgId, MessageCode.MSG_ID_NOT_FOUND.getCode(), "Valid actions: " +
List.of("create", "update_status", "update", "delete"));
};
} catch (Exception e) {
log.error("Error handling complaint request", e);
return errorResponse(msgId, MessageCode.INVALID_JSON_BODY.getCode(), e.getMessage());
}
}
private BaseResponse create(Integer msgId, ComplaintRequest req) {
if (req.getViolationId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(),
"violation_id is required");
if (req.getComplaintText() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(),
"text is required");
Long violationId = req.getViolationId();
if (complaintEntityRepository.existsByViolationId(violationId)) {
return errorResponse(msgId, MessageCode.COMPLAINT_ALREADY_EXIST.getCode(),
MessageCode.COMPLAINT_ALREADY_EXIST.getDescription());
}
return successResponse(msgId, "Complaint created successfully", complaintService.createComplaint(req));
}
private BaseResponse updateStatus(Integer msgId, ComplaintRequest req) {
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
if (req.getStatus() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "status is required");
List<String> statuses = Arrays.stream(ComplaintStatus.values()).map(ComplaintStatus::name).toList();
if (statuses.stream().noneMatch(status -> status.equals(req.getStatus().toUpperCase()))) {
return errorResponse(msgId, MessageCode.NOT_VALID_STATUS.getCode(), "Valid statuses: " + statuses);
}
ComplaintStatus status = ComplaintStatus.valueOf(req.getStatus().toUpperCase());
ComplaintEntity complaintEntity = complaintEntityRepository.findById(req.getId()).orElse(null);
if (complaintEntity == null) {
return errorResponse(msgId, MessageCode.COMPLAINT_NOT_FOUND.getCode(),
MessageCode.COMPLAINT_NOT_FOUND.getDescription());
}
ComplaintResponse response = complaintService.updateComplaintStatus(complaintEntity, status);
return successResponse(msgId, "Status updated successfully", response);
}
private BaseResponse update(Integer msgId, ComplaintRequest req) {
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
ComplaintEntity complaintEntity = complaintEntityRepository.findById(req.getId()).orElse(null);
if (complaintEntity == null) {
return errorResponse(msgId, MessageCode.COMPLAINT_NOT_FOUND.getCode(),
MessageCode.COMPLAINT_NOT_FOUND.getDescription());
}
ComplaintResponse response = complaintService.updateComplaint(req.getId(), req);
return successResponse(msgId, "Complaint updated successfully", response);
}
private BaseResponse delete(Integer msgId, ComplaintRequest req) {
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
ComplaintResponse response = complaintService.deleteComplaint(req.getId());
return successResponse(msgId, "Complaint deleted successfully", response);
}
private BaseResponse successResponse(Integer msgId, String message, Object data) {
return new BaseResponse(msgId, MessageCode.SUCCESS.getCode(), message, data);
}
private BaseResponse errorResponse(Integer msgId, Integer code, String message) {
return new BaseResponse(msgId, code, message, new HashMap<>());
}
}
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -9,12 +10,11 @@ import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.cost.CostRequest; import ru.soune.nocopy.dto.cost.CostRequest;
import ru.soune.nocopy.dto.cost.CostResponse; import ru.soune.nocopy.dto.cost.CostResponse;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.service.cost.CostService; import ru.soune.nocopy.service.cost.CostService;
import ru.soune.nocopy.service.user.UserService;
import java.util.Optional; import java.util.Map;
@Slf4j @Slf4j
@Component @Component
@@ -23,10 +23,12 @@ public class CostHandler implements RequestHandler {
private final CostService costService; private final CostService costService;
private final AuthTokenRepository authTokenRepository; private final HttpServletRequest httpServletRequest;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final UserService userService;
private final Integer MAX_FILES_FOR_CHECK = 1000; private final Integer MAX_FILES_FOR_CHECK = 1000;
@Override @Override
@@ -64,18 +66,17 @@ public class CostHandler implements RequestHandler {
} }
private BaseResponse handleCheckTokensForFilesProtect(CostRequest costRequest, BaseRequest request) { private BaseResponse handleCheckTokensForFilesProtect(CostRequest costRequest, BaseRequest request) {
String authToken = costRequest.getAuthToken(); Long userId = (Long) httpServletRequest.getAttribute("userId");
Optional<AuthToken> token = authTokenRepository.findByToken(authToken); User user = userService.getUserById(userId).orElse(null);
if (token.isEmpty()) { if (user == null) {
return new BaseResponse( return new BaseResponse(
request.getMsgId(), request.getMsgId(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(), MessageCode.USER_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(), MessageCode.USER_NOT_FOUND.getDescription(),
null); Map.of("User: ", userId));
} }
User user = token.get().getUser();
Integer tokens = user.getActiveTariffInfo().getTokens(); Integer tokens = user.getActiveTariffInfo().getTokens();
int cost = costService.protectFileCost(costRequest.getFileType()); int cost = costService.protectFileCost(costRequest.getFileType());
@@ -0,0 +1,125 @@
package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.docviewer.DocViewerRequest;
import ru.soune.nocopy.dto.docviewer.DockViewStatsResponse;
import ru.soune.nocopy.dto.file.ActionResponse;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.exception.NotFoundAuthToken;
import ru.soune.nocopy.service.dockview.DockViewService;
import ru.soune.nocopy.service.file.FileEntityService;
import java.util.Arrays;
import java.util.List;
@Component
@RequiredArgsConstructor
@Slf4j
public class DockViewFileHandler implements RequestHandler {
private final DockViewService dockViewService;
private final FileEntityService fileEntityService;
private final ObjectMapper objectMapper;
private final HttpServletRequest httpServletRequest;
@Override
public BaseResponse handle(BaseRequest request) throws Exception {
DocViewerRequest docViewerRequest = objectMapper.convertValue(request.getMessageBody(), DocViewerRequest.class);
String action = docViewerRequest.getAction();
switch (action) {
case "history_view":
return handleGetHistory(request, docViewerRequest);
case "view_stats":
return handleGetViewStats(request, docViewerRequest);
default:
ActionResponse response = ActionResponse.builder()
.action(action)
.availableActions(Arrays.asList("history_view", "view_stats"))
.build();
return new BaseResponse(request.getMsgId(), MessageCode.INVALID_ACTION.getCode(),
"Invalid action: " + action, response);
}
}
private BaseResponse handleGetHistory(BaseRequest request, DocViewerRequest docViewerRequest) {
try {
Long userId = (Long) httpServletRequest.getAttribute("userId");
List<String> fileIds = fileEntityService.getAllUserFiles(userId)
.stream()
.filter(fileEntity -> fileEntity.getMimeType().equals("document"))
.map(FileEntity::getId)
.toList();
if (fileIds.isEmpty()) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
"Files for search not found",
null);
}
DockViewStatsResponse openLastHistory = dockViewService.getOpenLastHistory(docViewerRequest.getPage(),
docViewerRequest.getSize(), docViewerRequest.getSortDirection(), docViewerRequest.getSortBy(),
fileIds, docViewerRequest.getLocale());
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
openLastHistory);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error getting view history", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
"Failed to get file view history: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetViewStats(BaseRequest request, DocViewerRequest docViewerRequest) {
try {
Long userId = (Long) httpServletRequest.getAttribute("userId");
List<String> fileIds = fileEntityService.getAllUserFiles(userId)
.stream()
.filter(fileEntity -> fileEntity.getMimeType().equals("document"))
.map(FileEntity::getId)
.toList();
if (fileIds.isEmpty()) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
"Files for search not found",
null);
}
DockViewStatsResponse totalStats = dockViewService.getTotalStatsByFileIds(fileIds,
docViewerRequest.getLocale());
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
totalStats);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
}
}
}
@@ -1,30 +1,29 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import ru.soune.nocopy.dto.*; import ru.soune.nocopy.dto.*;
import ru.soune.nocopy.dto.file.*; import ru.soune.nocopy.dto.file.*;
import ru.soune.nocopy.entity.file.FileAppeal; import ru.soune.nocopy.entity.file.*;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.file.FileStatus;
import ru.soune.nocopy.entity.file.ProtectionStatus;
import ru.soune.nocopy.entity.file.moderation.ModerationLog; import ru.soune.nocopy.entity.file.moderation.ModerationLog;
import ru.soune.nocopy.entity.file.permission.PermissionType;
import ru.soune.nocopy.exception.*; import ru.soune.nocopy.exception.*;
import ru.soune.nocopy.repository.FileAppealRepository; import ru.soune.nocopy.repository.*;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.service.file.cloud.CloudStorageService; import ru.soune.nocopy.service.file.cloud.CloudStorageService;
import ru.soune.nocopy.repository.ModerationLogRepository;
import ru.soune.nocopy.service.file.moderation.ModerationService; import ru.soune.nocopy.service.file.moderation.ModerationService;
import ru.soune.nocopy.service.register.AuthService; import ru.soune.nocopy.service.file.permission.FileAccessService;
import ru.soune.nocopy.service.file.FileEntityService; import ru.soune.nocopy.service.file.FileEntityService;
import ru.soune.nocopy.service.file.FileStatsService; import ru.soune.nocopy.service.file.FileStatsService;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -36,14 +35,14 @@ public class FileEntityHandler implements RequestHandler {
private final FileEntityService fileEntityService; private final FileEntityService fileEntityService;
private final AuthService authService;
private final FileStatsService fileStatsService; private final FileStatsService fileStatsService;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final FileEntityRepository fileEntityRepository; private final FileEntityRepository fileEntityRepository;
private final FileMonitoringRepository fileMonitoringRepository;
private final CloudStorageService cloudStorageService; private final CloudStorageService cloudStorageService;
private final ModerationService moderationService; private final ModerationService moderationService;
@@ -52,6 +51,12 @@ public class FileEntityHandler implements RequestHandler {
private final ModerationLogRepository moderationLogRepository; private final ModerationLogRepository moderationLogRepository;
private final ImageHashRepository imageHashRepository;
private final FileAccessService fileAccessService;
private final HttpServletRequest httpServletRequest;
@Override @Override
public BaseResponse handle(BaseRequest request) { public BaseResponse handle(BaseRequest request) {
try { try {
@@ -77,18 +82,14 @@ public class FileEntityHandler implements RequestHandler {
return handleProtectFile(request, fileRequest); return handleProtectFile(request, fileRequest);
case "delete_file": case "delete_file":
return handleDeleteFile(request, fileRequest); return handleDeleteFile(request, fileRequest);
case "change_file_status": case "delete_files":
return handleChangeStatus(request, fileRequest); return handleDeleteFiles(request, fileRequest);
case "moderate_file":
return handleModerateFile(request, fileRequest);
case "submit_appeal": case "submit_appeal":
return handleSubmitAppeal(request, fileRequest); return handleSubmitAppeal(request, fileRequest);
case "review_appeal":
return handleReviewAppeal(request, fileRequest);
case "user_appeals": case "user_appeals":
return handleGetUserAppeals(request, fileRequest); return handleGetUserAppeals(request, fileRequest);
case "files_for_moderation": case "change_permission":
return handleGetFilesForModeration(request, fileRequest); return handleChangePermission(request, fileRequest);
default: default:
ActionResponse response = ActionResponse.builder() ActionResponse response = ActionResponse.builder()
.action(action) .action(action)
@@ -113,7 +114,7 @@ public class FileEntityHandler implements RequestHandler {
} }
private BaseResponse handleGetFilesUserInfo(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleGetFilesUserInfo(BaseRequest request, FileEntityRequest fileRequest) {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
FileInfoUserResponse userFileStats = fileStatsService.getUserFileStats(userId); FileInfoUserResponse userFileStats = fileStatsService.getUserFileStats(userId);
return new BaseResponse(request.getMsgId(), return new BaseResponse(request.getMsgId(),
@@ -124,7 +125,7 @@ public class FileEntityHandler implements RequestHandler {
private BaseResponse handleGetFileInfo(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleGetFileInfo(BaseRequest request, FileEntityRequest fileRequest) {
try { try {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
FileEntityResponse fileInfo = fileEntityService.getById(fileRequest.getFileId(), request.getVersion()); FileEntityResponse fileInfo = fileEntityService.getById(fileRequest.getFileId(), request.getVersion());
if (!fileInfo.getUserId().equals(userId)) { if (!fileInfo.getUserId().equals(userId)) {
@@ -153,9 +154,60 @@ public class FileEntityHandler implements RequestHandler {
} }
} }
private BaseResponse handleChangePermission(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = (Long) httpServletRequest.getAttribute("userId");
FileEntityResponse fileInfo = fileEntityService.getById(fileRequest.getFileId(), request.getVersion());
if (!fileInfo.getUserId().equals(userId)) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
"Access denied",
null);
}
Map<String, Boolean> permissions = fileRequest.getPermissions();
if (!PermissionType.areAllValid(permissions)) {
return new BaseResponse(request.getMsgId(),
MessageCode.PERMISSION_NOT_VALID.getCode(),
MessageCode.PERMISSION_NOT_VALID.getDescription(),
null);
}
for (Map.Entry<String, Boolean> entry: permissions.entrySet()) {
try {
fileAccessService.changePermission(fileInfo.getId(), PermissionType.valueOf(entry.getKey()),
entry.getValue());
} catch (FileEntityNotFoundException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
MessageCode.FILE_NOT_FOUND.getDescription(),
null);
}
}
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
fileInfo);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error getting file info", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to get file info: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetFileBySession(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleGetFileBySession(BaseRequest request, FileEntityRequest fileRequest) {
try { try {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
FileEntityResponse fileInfo = fileEntityService.getByUploadSessionId(fileRequest.getUploadSessionId(), FileEntityResponse fileInfo = fileEntityService.getByUploadSessionId(fileRequest.getUploadSessionId(),
request.getVersion()); request.getVersion());
@@ -187,7 +239,7 @@ public class FileEntityHandler implements RequestHandler {
private BaseResponse handleGetUserFiles(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleGetUserFiles(BaseRequest request, FileEntityRequest fileRequest) {
try { try {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1; int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20; int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
@@ -212,74 +264,9 @@ public class FileEntityHandler implements RequestHandler {
} }
} }
private BaseResponse handleChangeStatus(BaseRequest request, FileEntityRequest fileRequest) {
FileStatus newStatus = fileRequest.getFileStatus();
String fileId = fileRequest.getFileId();
try {
fileEntityService.changeFileStatus(newStatus ,fileRequest.getFileId());
} catch (FileEntityNotFoundException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
MessageCode.FILE_NOT_FOUND.getDescription(),
FileEntityResponse.builder().id(fileId).build());
}
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
Map.of("file_status", newStatus, "file_id", fileId));
}
// private BaseResponse handleSearchFiles(BaseRequest request, FileEntityRequest fileRequest) {
// try {
// Long userId = authService.useUserAuthToken(fileRequest.getToken());
// int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
// int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
// String fileRequestSortBy = fileRequest.getSortBy();
// String sortBy = !fileRequestSortBy.equals("") ? fileRequest.getSortBy(): "createdAt";
// sortBy = sortBy.equals("fileName") ? "originalFileName" : sortBy;
//
// String sortOrder = fileRequest.getSortOrder();
// Sort.Direction direction = (sortOrder != null && sortOrder.equalsIgnoreCase("desc"))
// ? Sort.Direction.DESC
// : Sort.Direction.ASC;
// Sort sort = Sort.by(direction, sortBy);
//
// Pageable pageable = PageRequest.of(page, pageSize, sort);
// FileResponse userFiles = fileEntityService.getUserFiles(userId, pageable, request.getVersion());
//
// FileListResponse response = FileListResponse.builder()
// .files(userFiles.getFiles())
// .totalCount(userFiles.getTotalCount())
// .totalSize(userFiles.getTotalSize())
// .formattedTotalSize(fileEntityService.formatFileSize(userFiles.getTotalSize()))
// .page(page)
// .pageSize(pageSize)
// .sortBy(sortBy)
// .sortOrder(sortOrder)
// .build();
//
// return new BaseResponse(request.getMsgId(),
// MessageCode.SUCCESS.getCode(),
// MessageCode.SUCCESS.getDescription(),
// response);
//
// } catch (NotFoundAuthToken e) {
// return new BaseResponse(request.getMsgId(),
// MessageCode.INVALID_TOKEN.getCode(),
// "Authentication required", null);
// } catch (Exception e) {
// log.error("Error searching files", e);
// return new BaseResponse(request.getMsgId(),
// MessageCode.FILE_UPLOAD_ERROR.getCode(),
// "Failed to search files: " + e.getMessage(), null);
// }
// }
private BaseResponse handleSearchFiles(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleSearchFiles(BaseRequest request, FileEntityRequest fileRequest) {
try { try {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1; int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20; int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
@@ -341,73 +328,6 @@ public class FileEntityHandler implements RequestHandler {
} }
} }
/**
*
* private BaseResponse handleSearchFiles(BaseRequest request, FileEntityRequest fileRequest) {
* try {
* Long userId = authService.useUserAuthToken(fileRequest.getToken());
* int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
* int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
*
* String sortBy = fileRequest.getSortBy() != null ? fileRequest.getSortBy() : "fileName";
* SortOrder sortOrder = SortOrder.fromString(fileRequest.getSortOrder());
*
* FileResponse allFiles = fileEntityService.getUserFiles(userId, 1, 1000, request.getVersion());
*
* String searchQuery = fileRequest.getQuery() != null ? fileRequest.getQuery().toLowerCase().trim() : "";
* String[] searchTerms = searchQuery.split("\\s+");
* String filterType = fileRequest.getType();
* String dateFilter = fileRequest.getDateFilter();
*
* List<FileEntityResponse> filteredFiles = allFiles.getFiles().stream()
* .filter(f -> matchesSearch(f, searchTerms, searchQuery, filterType))
* .filter(f -> matchesDateFilter(f, dateFilter))
* .collect(Collectors.toList());
*
* Comparator<FileEntityResponse> comparator = getComparator(sortBy, sortOrder);
* filteredFiles.sort(comparator);
*
* int start = (page - 1) * pageSize;
* int end = Math.min(start + pageSize, filteredFiles.size());
*
* if (start >= filteredFiles.size()) {
* return createEmptyResponse(request, page, pageSize, sortBy, sortOrder.getValue());
* }
*
* List<FileEntityResponse> paginatedFiles = filteredFiles.subList(start, end);
* long totalSize = paginatedFiles.stream()
* .mapToLong(FileEntityResponse::getFileSize)
* .sum();
*
* FileListResponse response = FileListResponse.builder()
* .files(paginatedFiles)
* .totalCount(filteredFiles.size())
* .totalSize(totalSize)
* .formattedTotalSize(fileEntityService.formatFileSize(totalSize))
* .page(page)
* .pageSize(pageSize)
* .sortBy(sortBy)
* .sortOrder(sortOrder.getValue())
* .build();
*
* return new BaseResponse(request.getMsgId(),
* MessageCode.SUCCESS.getCode(),
* MessageCode.SUCCESS.getDescription(),
* response);
*
* } catch (NotFoundAuthToken e) {
* return new BaseResponse(request.getMsgId(),
* MessageCode.INVALID_TOKEN.getCode(),
* "Authentication required", null);
* } catch (Exception e) {
* log.error("Error searching files", e);
* return new BaseResponse(request.getMsgId(),
* MessageCode.FILE_UPLOAD_ERROR.getCode(),
* "Failed to search files: " + e.getMessage(), null);
* }
* }
*/
private boolean matchesDateFilter(FileEntityResponse file, String dateFilter) { private boolean matchesDateFilter(FileEntityResponse file, String dateFilter) {
if (dateFilter == null || dateFilter.isEmpty()) { if (dateFilter == null || dateFilter.isEmpty()) {
return true; return true;
@@ -540,9 +460,15 @@ public class FileEntityHandler implements RequestHandler {
); );
break; break;
case "monitoring": case "monitoring":
Map<String, Integer> monitoringOrder = Map.of(
"MONITORING_DAILY", 1,
"MONITORING_WEEKLY", 2,
"MONITORING_MONTHLY", 3
);
comparator = Comparator.comparing( comparator = Comparator.comparing(
FileEntityResponse::getMonitoring, response -> monitoringOrder.getOrDefault(response.getMonitoring(),
Comparator.nullsLast(Comparator.naturalOrder()) Integer.MAX_VALUE), Comparator.nullsLast(Comparator.naturalOrder())
); );
break; break;
@@ -579,7 +505,7 @@ public class FileEntityHandler implements RequestHandler {
private BaseResponse handleGetUserFilesWithSort(BaseRequest request, FileEntityRequest fileRequest, private BaseResponse handleGetUserFilesWithSort(BaseRequest request, FileEntityRequest fileRequest,
String sortBy, SortOrder sortOrder) { String sortBy, SortOrder sortOrder) {
try { try {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1; int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20; int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
@@ -633,7 +559,7 @@ public class FileEntityHandler implements RequestHandler {
private BaseResponse handleGetStorageUsage(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleGetStorageUsage(BaseRequest request, FileEntityRequest fileRequest) {
try { try {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
long usage = fileEntityService.getUserStorageUsed(userId); long usage = fileEntityService.getUserStorageUsed(userId);
StorageUsageResponse response = StorageUsageResponse.builder() StorageUsageResponse response = StorageUsageResponse.builder()
@@ -684,9 +610,67 @@ public class FileEntityHandler implements RequestHandler {
request.getVersion())); request.getVersion()));
} }
@Transactional
public BaseResponse handleDeleteFiles(BaseRequest request, FileEntityRequest fileRequest) {
List<String> fileIds = fileRequest.getFileIds();
List<String> deletedIds = new ArrayList<>();
List<String> failedIds = new ArrayList<>();
for (String fileId : fileIds) {
try {
FileEntity fileEntity = fileEntityRepository.findById(fileId)
.orElseThrow(() -> new FileEntityNotFoundException(fileId));
deleteFileIfExists(fileEntity.getFilePath());
deleteFileIfExists(fileEntity.getProtectedFilePath());
deleteFileIfExists(fileEntity.getThumbnailPath());
deleteFileIfExists(fileEntity.getMediumPath());
deletedIds.add(fileId);
log.info("Physical files deleted for entity: {}", fileId);
} catch (Exception e) {
failedIds.add(fileId);
log.error("Failed to delete files for entity: {}", fileId, e);
}
}
if (!deletedIds.isEmpty()) {
fileMonitoringRepository.deleteAllByFileIdIn(deletedIds);
moderationLogRepository.deleteAllByFileIdIn(deletedIds);
imageHashRepository.deleteAllByFileIdIn(deletedIds);
fileAppealRepository.deleteAllByFileIdIn(deletedIds);
fileEntityRepository.deleteAllByIdIn(deletedIds);
log.info("Deleted {} entities from database", deletedIds.size());
}
return new BaseResponse(
request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
failedIds
);
}
private void deleteFileIfExists(String filePath) {
if (filePath != null && !filePath.isEmpty()) {
try {
Path path = Paths.get(filePath);
boolean deleted = Files.deleteIfExists(path);
if (deleted) {
log.debug("Deleted file: {}", filePath);
}
} catch (IOException e) {
log.warn("Failed to delete file: {}", filePath, e);
throw new RuntimeException("Failed to delete file: " + filePath, e);
}
}
}
private BaseResponse handleDeleteFile(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleDeleteFile(BaseRequest request, FileEntityRequest fileRequest) {
try { try {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
String fileId = fileRequest.getFileId(); String fileId = fileRequest.getFileId();
FileEntityResponse fileInfo = fileEntityService.getById(fileId, request.getVersion()); FileEntityResponse fileInfo = fileEntityService.getById(fileId, request.getVersion());
DeleteFileResponse response; DeleteFileResponse response;
@@ -776,7 +760,7 @@ public class FileEntityHandler implements RequestHandler {
private BaseResponse handleSubmitAppeal(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleSubmitAppeal(BaseRequest request, FileEntityRequest fileRequest) {
try { try {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
AppealRequest appealRequest = AppealRequest.builder() AppealRequest appealRequest = AppealRequest.builder()
.fileId(fileRequest.getFileId()) .fileId(fileRequest.getFileId())
@@ -803,55 +787,9 @@ public class FileEntityHandler implements RequestHandler {
} }
} }
private BaseResponse handleReviewAppeal(BaseRequest request, FileEntityRequest fileRequest) {
try {
// TODO
// Long moderatorId = authService.useAdminAuthToken(fileRequest.getToken());
String appealId = fileRequest.getAppealId();
Boolean approve = fileRequest.getApprove();
String comment = fileRequest.getComment();
if (appealId == null || approve == null) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"appealId and approve are required",
null);
}
//TODO
moderationService.reviewAppeal(appealId, approve, comment, 0L);
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
"Appeal reviewed successfully",
Map.of(
"appealId", appealId,
"approved", approve,
"comment", comment
));
} catch (SecurityException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
"Admin access required",
null);
} catch (IllegalStateException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
e.getMessage(),
null);
} catch (Exception e) {
log.error("Error reviewing appeal", e);
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"Failed to review appeal: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetUserAppeals(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleGetUserAppeals(BaseRequest request, FileEntityRequest fileRequest) {
try { try {
Long userId = authService.useUserAuthToken(fileRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1; int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20; int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
@@ -884,72 +822,6 @@ public class FileEntityHandler implements RequestHandler {
} }
} }
private BaseResponse handleGetFilesForModeration(BaseRequest request, FileEntityRequest fileRequest) {
try {
//TODO
// authService.useAdminAuthToken(fileRequest.getToken());
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
Page<FileEntity> files = moderationService.getFilesForModeration(page - 1, pageSize);
List<Map<String, Object>> filesWithInfo = files.getContent().stream()
.map(file -> {
FileModerationInfo info = moderationService.getFileModerationInfo(file.getId());
Map<String, Object> fileMap = new HashMap<>();
fileMap.put("fileId", file.getId());
fileMap.put("fileName", file.getOriginalFileName());
fileMap.put("userId", file.getUserId());
fileMap.put("status", file.getStatus() != null ? file.getStatus().name() : null);
Map<String, Object> moderationInfoMap = new HashMap<>();
moderationInfoMap.put("hasActiveAppeal", info != null && info.getHasActiveAppeal());
if (info != null && info.getActiveAppeal() != null) {
Map<String, Object> appealInfoMap = new HashMap<>();
appealInfoMap.put("appealId", info.getActiveAppeal().getAppealId());
appealInfoMap.put("status", info.getActiveAppeal().getStatus());
appealInfoMap.put("createdAt", info.getActiveAppeal().getCreatedAt());
moderationInfoMap.put("appealInfo", appealInfoMap);
} else {
moderationInfoMap.put("appealInfo", null);
}
fileMap.put("moderationInfo", moderationInfoMap);
return fileMap;
})
.collect(Collectors.toList());
Map<String, Object> response = Map.of(
"files", filesWithInfo,
"totalCount", files.getTotalElements(),
"totalPages", files.getTotalPages(),
"currentPage", page,
"pageSize", pageSize
);
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
response);
} catch (SecurityException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
"Admin access required",
null);
} catch (Exception e) {
log.error("Error getting files for moderation", e);
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"Failed to get files: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetFileModerationInfo(BaseRequest request, FileEntityRequest fileRequest) { private BaseResponse handleGetFileModerationInfo(BaseRequest request, FileEntityRequest fileRequest) {
try { try {
// TODO // TODO
@@ -0,0 +1,171 @@
package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.file.ActionResponse;
import ru.soune.nocopy.dto.file.AppealResponse;
import ru.soune.nocopy.dto.file.FileEntityRequest;
import ru.soune.nocopy.dto.file.FileModerationInfo;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.service.file.moderation.ModerationService;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
@Slf4j
@RequiredArgsConstructor
public class FileInteranlInfoHandler implements RequestHandler {
private final ObjectMapper objectMapper;
private final ModerationService moderationService;
@Value("${server.baseurl}")
private String baseUrl;
@Override
public BaseResponse handle(BaseRequest request) throws Exception {
try {
FileEntityRequest fileRequest = objectMapper.convertValue(
request.getMessageBody(), FileEntityRequest.class);
String action = fileRequest.getAction();
switch (action) {
case "files_for_moderation":
return handleGetFilesForModeration(request, fileRequest);
case "all_appeals":
return handleGetAllAppeals(request, fileRequest);
default:
ActionResponse response = ActionResponse.builder()
.action(action)
.availableActions(Arrays.asList("files_for_moderation", "all_appeals"))
.build();
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_ACTION.getCode(),
"Invalid action: " + action,
response);
}
} catch (Exception e) {
log.error("Error in FileEntityHandler", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Handler error: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetFilesForModeration(BaseRequest request, FileEntityRequest fileRequest) {
try {
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 0;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
Page<FileEntity> files = moderationService.getFilesForModeration(page, pageSize,
fileRequest.getSortOrder(), fileRequest.getSortBy());
List<Map<String, Object>> filesWithInfo = files.getContent().stream()
.map(file -> {
FileModerationInfo info = moderationService.getFileModerationInfo(file.getId());
Map<String, Object> fileMap = new HashMap<>();
fileMap.put("fileId", file.getId());
fileMap.put("fileName", file.getOriginalFileName());
fileMap.put("downloadUrl", "/api/admin/download/" + file.getId());
fileMap.put("image", baseUrl + "/api/files/protected/" + file.getId() + "/thumbnail");
fileMap.put("userId", file.getUserId());
fileMap.put("status", file.getStatus() != null ? file.getStatus().name() : null);
Map<String, Object> moderationInfoMap = new HashMap<>();
moderationInfoMap.put("hasActiveAppeal", info != null && info.getHasActiveAppeal());
if (info != null && info.getActiveAppeal() != null) {
Map<String, Object> appealInfoMap = new HashMap<>();
appealInfoMap.put("appealId", info.getActiveAppeal().getAppealId());
appealInfoMap.put("status", info.getActiveAppeal().getStatus());
appealInfoMap.put("createdAt", info.getActiveAppeal().getCreatedAt());
moderationInfoMap.put("appealInfo", appealInfoMap);
} else {
moderationInfoMap.put("appealInfo", null);
}
fileMap.put("moderationInfo", moderationInfoMap);
return fileMap;
})
.collect(Collectors.toList());
Map<String, Object> response = Map.of(
"files", filesWithInfo,
"totalCount", files.getTotalElements(),
"totalPages", files.getTotalPages(),
"currentPage", page,
"pageSize", pageSize
);
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
response);
} catch (SecurityException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
"Admin access required",
null);
} catch (Exception e) {
log.error("Error getting files for moderation", e);
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"Failed to get files: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetAllAppeals(BaseRequest request, FileEntityRequest fileRequest) {
try {
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 0;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
Page<AppealResponse> appeals = moderationService.getAllAppeals(page, pageSize,
fileRequest.getSortOrder(), fileRequest.getSortBy());
Map<String, Object> response = Map.of(
"appeals", appeals.getContent(),
"totalCount", appeals.getTotalElements(),
"totalPages", appeals.getTotalPages(),
"currentPage", page,
"pageSize", pageSize);
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
response);
} catch (SecurityException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error getting user appeals", e);
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"Failed to get appeals: " + e.getMessage(),
null);
}
}
}
@@ -0,0 +1,160 @@
package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.file.ActionResponse;
import ru.soune.nocopy.dto.file.FileEntityRequest;
import ru.soune.nocopy.dto.file.FileEntityResponse;
import ru.soune.nocopy.dto.file.ModerationActionRequest;
import ru.soune.nocopy.entity.file.FileStatus;
import ru.soune.nocopy.exception.FileEntityNotFoundException;
import ru.soune.nocopy.service.file.FileEntityService;
import ru.soune.nocopy.service.file.moderation.ModerationService;
import java.util.Arrays;
import java.util.Map;
@Component
@Slf4j
@RequiredArgsConstructor
public class FileInternalControlHandler implements RequestHandler {
private final ObjectMapper objectMapper;
private final ModerationService moderationService;
private final FileEntityService fileEntityService;
@Override
public BaseResponse handle(BaseRequest request) throws Exception {
try {
FileEntityRequest fileRequest = objectMapper.convertValue(request.getMessageBody(), FileEntityRequest.class);
String action = fileRequest.getAction();
switch (action) {
case "moderate_file":
return handleModerateFile(request, fileRequest);
case "review_appeal":
return handleReviewAppeal(request, fileRequest);
case "change_file_status":
return handleChangeStatus(request, fileRequest);
default:
ActionResponse response = ActionResponse.builder()
.action(action)
.availableActions(Arrays.asList(
"moderate_file", "change_file_status", "review_appeal"))
.build();
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_ACTION.getCode(),
"Invalid action: " + action,
response);
}
} catch (Exception e) {
log.error("Error in FileEntityHandler", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Handler error: " + e.getMessage(),
null);
}
}
private BaseResponse handleChangeStatus(BaseRequest request, FileEntityRequest fileRequest) {
FileStatus newStatus = fileRequest.getFileStatus();
String fileId = fileRequest.getFileId();
try {
fileEntityService.changeFileStatus(newStatus ,fileRequest.getFileId());
} catch (FileEntityNotFoundException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
MessageCode.FILE_NOT_FOUND.getDescription(),
FileEntityResponse.builder().id(fileId).build());
}
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
Map.of("file_status", newStatus, "file_id", fileId));
}
private BaseResponse handleReviewAppeal(BaseRequest request, FileEntityRequest fileRequest) {
try {
String appealId = fileRequest.getAppealId();
Boolean approve = fileRequest.getApprove();
String comment = fileRequest.getComment() == null ? "": fileRequest.getComment();
if (appealId == null || approve == null) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"appealId and approve are required",
null);
}
moderationService.reviewAppeal(appealId, approve, comment, request.getAdminId());
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
"Appeal reviewed successfully",
Map.of(
"appealId", appealId,
"approved", approve,
"comment", comment
));
} catch (SecurityException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
"Admin access required", null);
} catch (IllegalStateException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
e.getMessage(),
null);
} catch (Exception e) {
log.error("Error reviewing appeal", e);
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"Failed to review appeal: " + e.getMessage(),
null);
}
}
private BaseResponse handleModerateFile(BaseRequest request, FileEntityRequest fileRequest) {
try {
ModerationActionRequest moderationRequest = ModerationActionRequest.builder()
.fileId(fileRequest.getFileId())
.newStatus(fileRequest.getFileStatus())
.comment(fileRequest.getComment())
.build();
moderationService.moderateFile(moderationRequest, request.getAdminId());
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS_MODERATION.getCode(),
MessageCode.SUCCESS_MODERATION.getDescription(),
Map.of("file_id", fileRequest.getFileId()));
} catch (SecurityException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
MessageCode.ACCESS_DENIED.getDescription(),
Map.of("file_id", fileRequest.getFileId()));
} catch (FileEntityNotFoundException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
MessageCode.FILE_NOT_FOUND.getDescription(),
Map.of("file_id", fileRequest.getFileId()));
} catch (IllegalStateException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.ILLEGAL_STATE.getCode(),
MessageCode.ILLEGAL_STATE.getDescription(),
Map.of("file_id", fileRequest.getFileId()));
}
}
}
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@@ -10,14 +11,11 @@ import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError; import org.springframework.validation.FieldError;
import ru.soune.nocopy.dto.*; import ru.soune.nocopy.dto.*;
import ru.soune.nocopy.dto.file.*; import ru.soune.nocopy.dto.file.*;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.file.FileType; import ru.soune.nocopy.entity.file.FileType;
import ru.soune.nocopy.entity.file.FileUploadSession; import ru.soune.nocopy.entity.file.FileUploadSession;
import ru.soune.nocopy.exception.*; import ru.soune.nocopy.exception.*;
import ru.soune.nocopy.handler.validator.FileUploadRequestValidator; import ru.soune.nocopy.handler.validator.FileUploadRequestValidator;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.repository.FileUploadSessionRepository; import ru.soune.nocopy.repository.FileUploadSessionRepository;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.file.FileUploadService; import ru.soune.nocopy.service.file.FileUploadService;
import java.util.*; import java.util.*;
@@ -29,16 +27,14 @@ import java.util.stream.Collectors;
public class FileUploadHandler implements RequestHandler { public class FileUploadHandler implements RequestHandler {
private final FileUploadService fileUploadService; private final FileUploadService fileUploadService;
private final AuthService authService;
private final AuthTokenRepository authTokenRepository;
private final FileUploadSessionRepository fileUploadSessionRepository; private final FileUploadSessionRepository fileUploadSessionRepository;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final FileUploadRequestValidator fileUploadRequestValidator; private final FileUploadRequestValidator fileUploadRequestValidator;
private final HttpServletRequest httpServletRequest;
@Value("${file.storage.max-file-size}") @Value("${file.storage.max-file-size}")
private long maxFileSize; private long maxFileSize;
@@ -80,16 +76,7 @@ public class FileUploadHandler implements RequestHandler {
} }
private BaseResponse handleInitUpload(BaseRequest request, FileUploadRequest fileRequest) { private BaseResponse handleInitUpload(BaseRequest request, FileUploadRequest fileRequest) {
String token = fileRequest.getToken(); Long userId = (Long) httpServletRequest.getAttribute("userId");
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(token);
if (tokenOptional.isEmpty()) {
return new BaseResponse(request.getMsgId(), MessageCode.INVALID_TOKEN.getCode(),
MessageCode.INVALID_TOKEN.getDescription(), Map.of("token", token));
}
Long userId = authService.useUserAuthToken(token);
BindingResult bindingResult = new BeanPropertyBindingResult(fileRequest, "fileRequest"); BindingResult bindingResult = new BeanPropertyBindingResult(fileRequest, "fileRequest");
fileUploadRequestValidator.validate(fileRequest, bindingResult); fileUploadRequestValidator.validate(fileRequest, bindingResult);
@@ -219,7 +206,6 @@ public class FileUploadHandler implements RequestHandler {
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(), response); MessageCode.SUCCESS.getDescription(), response);
} catch (Exception e) { } catch (Exception e) {
log.error("Error getting file types", e); log.error("Error getting file types", e);
return new BaseResponse(request.getMsgId(), MessageCode.FILE_UPLOAD_ERROR.getCode(), return new BaseResponse(request.getMsgId(), MessageCode.FILE_UPLOAD_ERROR.getCode(),
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -8,12 +9,8 @@ import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.search.GlobalSearchStatisticsRequest; import ru.soune.nocopy.dto.search.GlobalSearchStatisticsRequest;
import ru.soune.nocopy.dto.search.GlobalSearchStatisticsResponse; import ru.soune.nocopy.dto.search.GlobalSearchStatisticsResponse;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.service.search.GlobalSearchStatisticsService; import ru.soune.nocopy.service.search.GlobalSearchStatisticsService;
import java.util.Optional;
@Slf4j @Slf4j
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -23,28 +20,17 @@ public class GlobalSearchHandler implements RequestHandler {
private final GlobalSearchStatisticsService statisticsService; private final GlobalSearchStatisticsService statisticsService;
private final AuthTokenRepository authTokenRepository; private final HttpServletRequest httpServletRequest;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
GlobalSearchStatisticsRequest statRequest = objectMapper.convertValue( GlobalSearchStatisticsRequest statRequest = objectMapper.convertValue(
request.getMessageBody(), GlobalSearchStatisticsRequest.class); request.getMessageBody(), GlobalSearchStatisticsRequest.class);
if (statRequest.getToken() == null) { Long userId = (Long) httpServletRequest.getAttribute("userId");
throw new IllegalArgumentException("User token is required");
}
Optional<AuthToken> tokenOptional = GlobalSearchStatisticsResponse statistics = statisticsService.getStatistics(userId, statRequest.getLimit(),
authTokenRepository.findByToken(statRequest.getToken()); statRequest.getDays());
if (tokenOptional.isEmpty()) {
throw new IllegalArgumentException("User token is required");
}
Long userId = tokenOptional.orElseThrow().getUser().getId();
GlobalSearchStatisticsResponse statistics = statisticsService.getStatistics(
userId, statRequest.getLimit(), statRequest.getDays());
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
@@ -1,6 +1,11 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.vrt.NoCopyFileService;
import com.vrt.fileprotection.FileProtector;
import com.vrt.fileprotection.NoCopyCheckResult;
import com.vrt.fileprotection.documents.DocumentCheckResult;
import com.vrt.fileprotection.image.ImageCheckResult;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -11,18 +16,32 @@ import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.file.ImageSearchRequest; import ru.soune.nocopy.dto.file.ImageSearchRequest;
import ru.soune.nocopy.dto.file.YandexSearchResponse; import ru.soune.nocopy.dto.file.YandexSearchResponse;
import ru.soune.nocopy.entity.file.FileEntity; import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.file.ImageHashEntity;
import ru.soune.nocopy.entity.tokenoperation.OperationType; import ru.soune.nocopy.entity.tokenoperation.OperationType;
import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.repository.FileEntityRepository; import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.repository.ImageHashRepository;
import ru.soune.nocopy.repository.SimilarImageProjection;
import ru.soune.nocopy.service.FileSimilarityService;
import ru.soune.nocopy.service.ImageHashService;
import ru.soune.nocopy.service.file.CheckCounterService; import ru.soune.nocopy.service.file.CheckCounterService;
import ru.soune.nocopy.service.file.FileUploadService;
import ru.soune.nocopy.service.search.SearchImageService; import ru.soune.nocopy.service.search.SearchImageService;
import ru.soune.nocopy.service.tariff.TariffConstants; import ru.soune.nocopy.service.tariff.TariffConstants;
import ru.soune.nocopy.service.tariff.TariffInfoService; import ru.soune.nocopy.service.tariff.TariffInfoService;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import static java.awt.SystemColor.info;
@Slf4j @Slf4j
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -40,6 +59,10 @@ public class ImageFoundRequestHandler implements RequestHandler {
private final SearchProperties searchProperties; private final SearchProperties searchProperties;
private final FileUploadService fileUploadService;
private final NoCopyFileService noCopyFileService;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
ImageSearchRequest imageSearchRequest = objectMapper.convertValue(request.getMessageBody(), ImageSearchRequest imageSearchRequest = objectMapper.convertValue(request.getMessageBody(),
@@ -125,6 +148,38 @@ public class ImageFoundRequestHandler implements RequestHandler {
int page = imageSearchRequest.getPage() != null ? imageSearchRequest.getPage() : 1; int page = imageSearchRequest.getPage() != null ? imageSearchRequest.getPage() : 1;
int pageSize = 5; int pageSize = 5;
boolean checkSimilar = imageSearchRequest.getCheckSimilarFirst() != null &&
imageSearchRequest.getCheckSimilarFirst();
if (checkSimilar && !allUniqueImages.isEmpty()) {
YandexSearchResponse.ImageResult image = allUniqueImages.getFirst();
String url = image.getUrl();
Path tempFile = null;
try {
tempFile = convertToSupportedFormat(fileUploadService.downloadImageFromUrl(url));
File file = tempFile.toFile();
NoCopyCheckResult checkResult = noCopyFileService.checkFile(file, FileProtector.Type.IMAGE);
if (checkResult instanceof ImageCheckResult.Success success) {
double watermarkCorrelation = success.getWatermarkCorrelation();
log.info("watermarkCorrelation: " + watermarkCorrelation);
if (watermarkCorrelation < 0.5) {
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
"Not found similar pictures", new YandexSearchResponse());
}
}
} finally {
if (tempFile != null) {
try {
Files.deleteIfExists(tempFile);
} catch (IOException e) {
log.warn("Not delete temp file: {}", tempFile, e);
}
}
}
}
List<YandexSearchResponse.ImageResult> pagedResults = searchImageService.paginateResults(allUniqueImages, page, List<YandexSearchResponse.ImageResult> pagedResults = searchImageService.paginateResults(allUniqueImages, page,
pageSize * 2); pageSize * 2);
@@ -140,4 +195,18 @@ public class ImageFoundRequestHandler implements RequestHandler {
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
message, finalResponse); message, finalResponse);
} }
public Path convertToSupportedFormat(Path imagePath) throws IOException {
String fileName = imagePath.getFileName().toString().toLowerCase();
if (fileName.matches(".*\\.(jpg|jpeg|png|bmp)$")) {
return imagePath;
}
BufferedImage image = ImageIO.read(imagePath.toFile());
Path pngFile = Files.createTempFile("converted_", ".png");
ImageIO.write(image, "PNG", pngFile.toFile());
return pngFile;
}
} }
@@ -2,6 +2,7 @@ package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.mail.MessagingException; import jakarta.mail.MessagingException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -15,20 +16,22 @@ import ru.soune.nocopy.dto.complaint.PaginatedResponse;
import ru.soune.nocopy.entity.complaint.LawCase; import ru.soune.nocopy.entity.complaint.LawCase;
import ru.soune.nocopy.entity.complaint.LawCasePriority; import ru.soune.nocopy.entity.complaint.LawCasePriority;
import ru.soune.nocopy.entity.complaint.LawCaseType; import ru.soune.nocopy.entity.complaint.LawCaseType;
import ru.soune.nocopy.entity.file.FileType;
import ru.soune.nocopy.entity.tokenoperation.OperationType; import ru.soune.nocopy.entity.tokenoperation.OperationType;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.entity.violation.Violation;
import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.exception.TariffNotFoundException; import ru.soune.nocopy.exception.TariffNotFoundException;
import ru.soune.nocopy.exception.UserNotFoundException; import ru.soune.nocopy.exception.UserNotFoundException;
import ru.soune.nocopy.repository.UserRepository; import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.complaint.LawCaseService; import ru.soune.nocopy.service.complaint.LawCaseService;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.tariff.TariffConstants; import ru.soune.nocopy.service.tariff.TariffConstants;
import ru.soune.nocopy.service.tariff.TariffInfoService; import ru.soune.nocopy.service.tariff.TariffInfoService;
import ru.soune.nocopy.service.violation.ViolationService;
import ru.soune.nocopy.service.violation.ViolationStatus;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.*;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j @Slf4j
@@ -38,20 +41,21 @@ public class LawCaseHandler implements RequestHandler {
private final LawCaseService lawCaseService; private final LawCaseService lawCaseService;
private final AuthService authService;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final UserRepository userRepository; private final UserRepository userRepository;
private final TariffInfoService tariffInfoService; private final TariffInfoService tariffInfoService;
private final ViolationService violationService;
private final HttpServletRequest httpServletRequest;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
LawCaseRequest lawCaseRequest = objectMapper.convertValue(request.getMessageBody(), LawCaseRequest lawCaseRequest = objectMapper.convertValue(request.getMessageBody(),
LawCaseRequest.class); LawCaseRequest.class);
Long userId = authService.useUserAuthToken(lawCaseRequest.getToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
String action = lawCaseRequest.getAction(); String action = lawCaseRequest.getAction();
return switch (action) { return switch (action) {
@@ -73,20 +77,34 @@ public class LawCaseHandler implements RequestHandler {
} }
private BaseResponse getAllUserLawCases(Long userId, LawCaseRequest lawCaseRequest, BaseRequest request) { private BaseResponse getAllUserLawCases(Long userId, LawCaseRequest lawCaseRequest, BaseRequest request) {
validateLawCaseRequestFilters(lawCaseRequest);
LawCaseType lawCaseType = lawCaseRequest.getFilterType() != null ?
LawCaseType.valueOf(lawCaseRequest.getFilterType().toUpperCase()) : null;
LawCasePriority lawCasePriority = lawCaseRequest.getFilterPriority() != null ?
LawCasePriority.valueOf(lawCaseRequest.getFilterPriority().toUpperCase()) : null;
Page<LawCase> lawCases = lawCaseService.getAllUserLawCases( Page<LawCase> lawCases = lawCaseService.getAllUserLawCases(
userId, userId,
lawCaseRequest.getPageSize(), lawCaseRequest.getPageSize(),
lawCaseRequest.getPageNumber(), lawCaseRequest.getPageNumber(),
lawCaseRequest.getFilterType(), lawCaseType,
lawCaseRequest.getFilterLawyer(), lawCaseRequest.getFilterLawyer(),
lawCaseRequest.getFilterPriority(), lawCasePriority,
lawCaseRequest.getViolationId(), lawCaseRequest.getViolationId(),
lawCaseRequest.getSortBy(), lawCaseRequest.getSortBy(),
lawCaseRequest.getSortDir()); lawCaseRequest.getSortDir());
List<LawCaseResponse> responses = lawCases.getContent().stream() List<LawCaseResponse> responses = new ArrayList<>();
.map(LawCaseResponse::fromEntity) List<LawCase> content = lawCases.getContent();
.collect(Collectors.toList());
for (LawCase lawCase: content) {
LawCaseResponse lawCaseResponse = LawCaseResponse.fromEntity(lawCase);
Violation violation = violationService.getById(lawCase.getViolationId());
if (violation != null) lawCaseResponse.setFileId(violation.getFileEntity().getId());
responses.add(lawCaseResponse);
}
PaginatedResponse<LawCaseResponse> paginatedResponse = new PaginatedResponse<>( PaginatedResponse<LawCaseResponse> paginatedResponse = new PaginatedResponse<>(
responses, responses,
@@ -101,6 +119,36 @@ public class LawCaseHandler implements RequestHandler {
MessageCode.SUCCESS.getDescription(), paginatedResponse); MessageCode.SUCCESS.getDescription(), paginatedResponse);
} }
private void validateLawCaseRequestFilters(LawCaseRequest lawCaseRequest) {
if (lawCaseRequest.getFilterPriority() != null) {
validateEnumValue(lawCaseRequest.getFilterPriority(),
LawCasePriority.class,
"filterPriority");
}
if (lawCaseRequest.getFilterType() != null) {
validateEnumValue(lawCaseRequest.getFilterType(),
LawCaseType.class,
"filterType");
}
}
private <T extends Enum<T>> void validateEnumValue(String value, Class<T> enumClass, String fieldName) {
boolean valid = Arrays.stream(enumClass.getEnumConstants())
.anyMatch(e -> e.name().equals(value));
if (!valid) {
throw new NotValidFieldException("Not valid " + fieldName,
new BaseResponse(30017, MessageCode.NOT_VALID_FIELD.getCode(),
MessageCode.NOT_VALID_FIELD.getDescription(),
Map.of("field", fieldName,
"valid_values", Arrays.stream(enumClass.getEnumConstants())
.map(Enum::name)
.collect(Collectors.toList()),
"received_value", value)));
}
}
private BaseResponse getLawCaseById(Long id, BaseRequest request) { private BaseResponse getLawCaseById(Long id, BaseRequest request) {
LawCase lawCase = lawCaseService.getById(id); LawCase lawCase = lawCaseService.getById(id);
@@ -114,6 +162,20 @@ public class LawCaseHandler implements RequestHandler {
} }
private BaseResponse createLawCase(Long userId, LawCaseRequest lawCaseRequest, BaseRequest request) { private BaseResponse createLawCase(Long userId, LawCaseRequest lawCaseRequest, BaseRequest request) {
validateRequiredParameters(lawCaseRequest, request, userId);
Long violationId = lawCaseRequest.getViolationId();
Violation violation = violationService.getById(violationId);
if (lawCaseService.lawCaseExistByViolationId(violationId)) {
return new BaseResponse(request.getMsgId(), MessageCode.LAW_CASE_ALREADY_EXIST.getCode(),
MessageCode.LAW_CASE_ALREADY_EXIST.getDescription(), "Law case was already exists");
}
if (violation != null && violation.getStatus().equals(ViolationStatus.NOT_OWNER_FILE.name())) {
return new BaseResponse(request.getMsgId(), MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
MessageCode.USER_NOT_HAD_PERMISSION.getDescription(), "Wrong status");
}
try { try {
tariffInfoService.writeOffTokens(userId, TariffConstants.LEGAL_COST, OperationType.CREATE_LEGAL_CASE); tariffInfoService.writeOffTokens(userId, TariffConstants.LEGAL_COST, OperationType.CREATE_LEGAL_CASE);
} catch (TariffNotFoundException e) { } catch (TariffNotFoundException e) {
@@ -125,8 +187,6 @@ public class LawCaseHandler implements RequestHandler {
MessageCode.INVALID_FIELD.getDescription(), Map.of("id", lawCaseRequest.getId())); MessageCode.INVALID_FIELD.getDescription(), Map.of("id", lawCaseRequest.getId()));
} }
validateRequiredParameters(lawCaseRequest, request);
User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("User not found")); User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("User not found"));
LawCase lawCase = lawCaseService.addLawCase( LawCase lawCase = lawCaseService.addLawCase(
@@ -134,7 +194,7 @@ public class LawCaseHandler implements RequestHandler {
lawCaseRequest.getDescription(), lawCaseRequest.getDescription(),
lawCaseRequest.getName(), lawCaseRequest.getName(),
LawCasePriority.valueOf(lawCaseRequest.getPriority()), LawCasePriority.valueOf(lawCaseRequest.getPriority()),
lawCaseRequest.getViolationId(), user); violationId, user);
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(), LawCaseResponse.fromEntity(lawCase)); MessageCode.SUCCESS.getDescription(), LawCaseResponse.fromEntity(lawCase));
@@ -188,13 +248,50 @@ public class LawCaseHandler implements RequestHandler {
MessageCode.SUCCESS.getDescription(), Map.of("id", id)); MessageCode.SUCCESS.getDescription(), Map.of("id", id));
} }
private void validateRequiredParameters(LawCaseRequest lawCaseRequest, BaseRequest request) { private void validateRequiredParameters(LawCaseRequest lawCaseRequest, BaseRequest request, Long userId) {
if (lawCaseRequest.getName() == null) throw new NotValidFieldException("Name is required", if (lawCaseRequest.getName() == null) throw new NotValidFieldException("Name is required",
new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FIELD.getCode(), new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FIELD.getCode(),
MessageCode.NOTION_NOT_FOUND.getDescription(), Map.of("fields", "name"))); MessageCode.NOT_VALID_FIELD.getDescription(), Map.of("fields", "name")));
if (lawCaseRequest.getDescription() == null) throw new NotValidFieldException("Description is required", if (lawCaseRequest.getDescription() == null) throw new NotValidFieldException("Description is required",
new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FIELD.getCode(), new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FIELD.getCode(),
MessageCode.NOTION_NOT_FOUND.getDescription(), Map.of("fields", "description"))); MessageCode.NOT_VALID_FIELD.getDescription(), Map.of("fields", "description")));
if (lawCaseRequest.getViolationId() == null) throw new NotValidFieldException("Violation id is required",
new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FIELD.getCode(),
MessageCode.NOT_VALID_FIELD.getDescription(), Map.of("fields", "violation_id")));
Violation violation = violationService.getById(lawCaseRequest.getViolationId());
if (!Objects.equals(violation.getFileEntity().getUserId(), userId))
throw new NotValidFieldException("Not user violation",
new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FIELD.getCode(),
MessageCode.NOT_VALID_FIELD.getDescription(), Map.of("fields", "violation_id")));
if (lawCaseRequest.getType() != null &&
!FileType.DOCUMENT.getDisplayName().equals(lawCaseRequest.getType().toLowerCase()) &&
!FileType.AUDIO.getDisplayName().equals(lawCaseRequest.getType().toLowerCase()) &&
!FileType.IMAGE.getDisplayName().equals(lawCaseRequest.getType().toLowerCase()) &&
!FileType.VIDEO.getDisplayName().equals(lawCaseRequest.getType().toLowerCase()))
throw new NotValidFieldException("Not valid type",
new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FIELD.getCode(),
MessageCode.NOT_VALID_FIELD.getDescription(), Map.of("valid_types",
List.of(FileType.DOCUMENT.getDisplayName(),
FileType.AUDIO.getDisplayName(),
FileType.IMAGE.getDisplayName(),
FileType.VIDEO.getDisplayName()))));
if (lawCaseRequest.getPriority() != null &&
!LawCasePriority.HIGH.name().equalsIgnoreCase(lawCaseRequest.getPriority()) &&
!LawCasePriority.LOW.name().equalsIgnoreCase(lawCaseRequest.getPriority()) &&
!LawCasePriority.MIDDLE.name().equalsIgnoreCase(lawCaseRequest.getPriority()) &&
!LawCasePriority.CRITICAL.name().equalsIgnoreCase(lawCaseRequest.getPriority()))
throw new NotValidFieldException("Not valid type",
new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FIELD.getCode(),
MessageCode.NOT_VALID_FIELD.getDescription(), Map.of("valid_types",
List.of(LawCasePriority.LOW.name(),
LawCasePriority.MIDDLE.name(),
LawCasePriority.HIGH.name(),
LawCasePriority.CRITICAL.name()))));
} }
} }
@@ -6,11 +6,10 @@ import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.*; import ru.soune.nocopy.dto.*;
import ru.soune.nocopy.dto.register.LoginAnswer; import ru.soune.nocopy.dto.register.LoginAnswer;
import ru.soune.nocopy.dto.register.LoginRequest; import ru.soune.nocopy.dto.register.LoginRequest;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.repository.UserRepository; import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.register.AuthService; import ru.soune.nocopy.util.JwtUtil;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
@@ -21,10 +20,10 @@ public class LoginRequestHandler implements RequestHandler {
private final UserRepository userRepository; private final UserRepository userRepository;
private final AuthService authService;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final JwtUtil jwtUtil;
@Override @Override
public BaseResponse handle(BaseRequest request) { public BaseResponse handle(BaseRequest request) {
LoginRequest loginRequest = objectMapper.convertValue(request.getMessageBody(), LoginRequest.class); LoginRequest loginRequest = objectMapper.convertValue(request.getMessageBody(), LoginRequest.class);
@@ -60,14 +59,11 @@ public class LoginRequestHandler implements RequestHandler {
MessageCode.PERMISSION_NOT_FOUND.getDescription(), loginAnswer); MessageCode.PERMISSION_NOT_FOUND.getDescription(), loginAnswer);
} }
AuthToken authToken = authService.login(loginRequest); String token = jwtUtil.generateToken(user.getId(), user.getEmail());
String token = authToken.getToken();
LoginAnswer loginAnswer = new LoginAnswer(); LoginAnswer loginAnswer = new LoginAnswer();
loginAnswer.setToken(token); loginAnswer.setToken(token);
authService.useUserAuthToken(token);
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(), loginAnswer); MessageCode.SUCCESS.getDescription(), loginAnswer);
} }
@@ -11,8 +11,6 @@ import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.repository.AuthTokenRepository; import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.repository.UserRepository; import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.register.AuthService;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
@@ -20,8 +18,6 @@ import java.util.Optional;
@RequiredArgsConstructor @RequiredArgsConstructor
public class LogoutRequestHandler implements RequestHandler { public class LogoutRequestHandler implements RequestHandler {
private final AuthService authService;
private final AuthTokenRepository authTokenRepository; private final AuthTokenRepository authTokenRepository;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
@@ -49,9 +45,6 @@ public class LogoutRequestHandler implements RequestHandler {
new LogoutRequest(logoutRequest.getEmail(), logoutRequest.getToken()))); new LogoutRequest(logoutRequest.getEmail(), logoutRequest.getToken())));
} }
authService.logout(logoutRequest.getToken());
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), MessageCode.SUCCESS.getDescription(), return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), MessageCode.SUCCESS.getDescription(),
new LogOutAnswer(logoutRequest.getEmail())); new LogOutAnswer(logoutRequest.getEmail()));
} }
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -10,11 +11,8 @@ import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.monitoring.MonitoringStatusResponse; import ru.soune.nocopy.dto.monitoring.MonitoringStatusResponse;
import ru.soune.nocopy.dto.monitoring.SetMonitoringRequest; import ru.soune.nocopy.dto.monitoring.SetMonitoringRequest;
import ru.soune.nocopy.entity.monitoring.MonitoringType; import ru.soune.nocopy.entity.monitoring.MonitoringType;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.UserNotHavePermission; import ru.soune.nocopy.exception.UserNotHavePermission;
import ru.soune.nocopy.service.monitoring.FileMonitoringService; import ru.soune.nocopy.service.monitoring.FileMonitoringService;
import ru.soune.nocopy.service.register.AuthService;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.util.Arrays; import java.util.Arrays;
@@ -29,24 +27,14 @@ public class MonitoringHandler implements RequestHandler {
private final FileMonitoringService monitoringService; private final FileMonitoringService monitoringService;
private final AuthService authService; private final HttpServletRequest httpServletRequest;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
SetMonitoringRequest setRequest = objectMapper.convertValue( SetMonitoringRequest setRequest = objectMapper.convertValue(
request.getMessageBody(), SetMonitoringRequest.class); request.getMessageBody(), SetMonitoringRequest.class);
String authToken = setRequest.getAuthToken(); Long userId = (Long) httpServletRequest.getAttribute("userId");
AuthToken userAuthToken = authService.getAuthToken(authToken);
if (authToken == null || userAuthToken == null) {
return new BaseResponse(30007, MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
Map.of("token", authToken));
}
User user = userAuthToken.getUser();
Long userId = user.getId();
String typeStr = setRequest.getMonitoringType(); String typeStr = setRequest.getMonitoringType();
MonitoringType monitoringType; MonitoringType monitoringType;
@@ -64,7 +52,7 @@ public class MonitoringHandler implements RequestHandler {
} catch (UserNotHavePermission e) { } catch (UserNotHavePermission e) {
return new BaseResponse(request.getMsgId(), return new BaseResponse(request.getMsgId(),
MessageCode.USER_NOT_HAD_PERMISSION.getCode(), MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
MessageCode.USER_NOT_HAD_PERMISSION.getDescription(), Map.of("token", authToken)); MessageCode.USER_NOT_HAD_PERMISSION.getDescription(), Map.of("User id: ", userId));
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
return new BaseResponse(request.getMsgId(), return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(), MessageCode.FILE_NOT_FOUND.getCode(),
@@ -0,0 +1,65 @@
package ru.soune.nocopy.handler;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.statistic.MonitoringStatisticResponse;
import ru.soune.nocopy.entity.company.Company;
import ru.soune.nocopy.entity.monitoring.MonitoringType;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.repository.FileMonitoringRepository;
import ru.soune.nocopy.repository.UserRepository;
import java.util.List;
@Slf4j
@Component
@RequiredArgsConstructor
public class MonitoringStatisticHandler implements RequestHandler {
private final FileMonitoringRepository fileMonitoringRepository;
private final UserRepository userRepository;
private final HttpServletRequest httpServletRequest;
@Override
public BaseResponse handle(BaseRequest request) throws Exception {
try {
Long userId = (Long) httpServletRequest.getAttribute("userId");
User user = userRepository.findById(userId).orElseThrow();
Company company = user.getCompany();
List<Long> userIds = company == null ? List.of(userId) :
user.getCompany()
.getUsers()
.stream()
.map(User::getId).toList();
MonitoringStatisticResponse monitoringStatisticResponse = MonitoringStatisticResponse.builder()
.everyDay(fileMonitoringRepository.countByUserIdsAndMonitoringType(userIds,
MonitoringType.MONITORING_DAILY))
.everyMonth(fileMonitoringRepository.countByUserIdsAndMonitoringType(userIds,
MonitoringType.MONITORING_MONTHLY))
.everyWeekly(fileMonitoringRepository.countByUserIdsAndMonitoringType(userIds,
MonitoringType.MONITORING_WEEKLY))
.build();
return new BaseResponse(
request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
monitoringStatisticResponse);
} catch (Exception e) {
return new BaseResponse(
request.getMsgId(),
MessageCode.INVALID_JSON_BODY.getCode(),
MessageCode.INVALID_JSON_BODY.getDescription(),
null);
}
}
}
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -14,7 +15,7 @@ import com.fasterxml.jackson.databind.type.TypeFactory;
import ru.soune.nocopy.dto.notification.*; import ru.soune.nocopy.dto.notification.*;
import ru.soune.nocopy.entity.notification.Notification; import ru.soune.nocopy.entity.notification.Notification;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.service.register.AuthService; import ru.soune.nocopy.service.user.UserService;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -31,7 +32,9 @@ public class NotificationHandler implements RequestHandler {
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final AuthService authService; private final HttpServletRequest httpServletRequest;
private final UserService userService;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
@@ -56,7 +59,16 @@ public class NotificationHandler implements RequestHandler {
case "list": { case "list": {
NotificationListRequest listRequest = objectMapper.convertValue(request.getMessageBody(), NotificationListRequest listRequest = objectMapper.convertValue(request.getMessageBody(),
NotificationListRequest.class); NotificationListRequest.class);
User user = authService.getUser(listRequest.getAuthToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
User user = userService.getUserById(userId).orElse(null);
if (user == null) {
return new BaseResponse(
request.getMsgId(),
MessageCode.USER_NOT_FOUND.getCode(),
MessageCode.USER_NOT_FOUND.getDescription(),
Map.of("User:", userId));
}
Page<Notification> page = notificationService.getAllNotifications( Page<Notification> page = notificationService.getAllNotifications(
user, user,
@@ -87,7 +99,8 @@ public class NotificationHandler implements RequestHandler {
case "active": { case "active": {
ActivateNotificationRequest activateRequest = objectMapper.convertValue(request.getMessageBody(), ActivateNotificationRequest activateRequest = objectMapper.convertValue(request.getMessageBody(),
ActivateNotificationRequest.class); ActivateNotificationRequest.class);
User user = authService.getUser(activateRequest.getAuthToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
User user = userService.getUserById(userId).orElse(null);
List<Notification> recent = notificationService.getActiveNotifications(user); List<Notification> recent = notificationService.getActiveNotifications(user);
@@ -107,7 +120,8 @@ public class NotificationHandler implements RequestHandler {
case "markRead": { case "markRead": {
MarkAsReadRequest markRequest = objectMapper.convertValue(request.getMessageBody(), MarkAsReadRequest markRequest = objectMapper.convertValue(request.getMessageBody(),
MarkAsReadRequest.class); MarkAsReadRequest.class);
User user = authService.getUser(markRequest.getAuthToken()); Long userId = (Long) httpServletRequest.getAttribute("userId");
User user = userService.getUserById(userId).orElse(null);
int updated = notificationService.markAsRead(user, markRequest.getNotificationIds()); int updated = notificationService.markAsRead(user, markRequest.getNotificationIds());
@@ -153,12 +167,23 @@ public class NotificationHandler implements RequestHandler {
} }
private NotificationDto toDto(Notification notification) { private NotificationDto toDto(Notification notification) {
Object contextObject = null;
if (notification.getContext() != null) {
try {
ObjectMapper objectMapper = new ObjectMapper();
contextObject = objectMapper.readValue(notification.getContext(), Object.class);
} catch (Exception e) {
contextObject = notification.getContext();
}
}
return NotificationDto.builder() return NotificationDto.builder()
.id(notification.getId()) .id(notification.getId())
.message(notification.getMessage()) .message(notification.getMessage())
.type(notification.getNotificationType()) .type(notification.getNotificationType())
.status(notification.getStatus()) .status(notification.getStatus())
.createdAt(notification.getCreatedAt()) .createdAt(notification.getCreatedAt())
.context(contextObject)
.build(); .build();
} }
} }
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.soune.ReferralInvitee; import ru.soune.ReferralInvitee;
@@ -11,8 +12,8 @@ import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.referral.ReferralRequest; import ru.soune.nocopy.dto.referral.ReferralRequest;
import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.repository.AuthTokenRepository; import ru.soune.nocopy.service.user.UserService;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -24,7 +25,9 @@ public class ReferralHandler implements RequestHandler {
private final ReferralService referralService; private final ReferralService referralService;
private final AuthTokenRepository authTokenRepository; private final HttpServletRequest httpServletRequest;
private final UserService userService;
private final ObjectMapper mapper = new ObjectMapper(); private final ObjectMapper mapper = new ObjectMapper();
@@ -32,20 +35,28 @@ public class ReferralHandler implements RequestHandler {
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
ReferralRequest referralRequest = mapper.convertValue(request.getMessageBody(), ReferralRequest.class); ReferralRequest referralRequest = mapper.convertValue(request.getMessageBody(), ReferralRequest.class);
String action = referralRequest.getAction(); String action = referralRequest.getAction();
String token = referralRequest.getToken(); Long userId = (Long) httpServletRequest.getAttribute("userId");
AuthToken authToken = authTokenRepository.findByToken(token).orElseThrow(); User user = userService.getUserById(userId).orElse(null);
if (user == null) {
return new BaseResponse(
request.getMsgId(),
MessageCode.USER_NOT_FOUND.getCode(),
MessageCode.USER_NOT_FOUND.getDescription(),
Map.of("User: ", userId));
}
switch (action) { switch (action) {
case "refill": case "refill":
return handleRefill(request, authToken.getUser().getId(), referralRequest.getAmount()); return handleRefill(request, userId, referralRequest.getAmount());
case "levels": case "levels":
return handleReferralLevels(request); return handleReferralLevels(request);
case "level": case "level":
return handleUserLevel(request, authToken.getUser().getId()); return handleUserLevel(request, userId);
case "userStats" : case "userStats" :
return handleUserStats(request, authToken.getUser().getId()); return handleUserStats(request, userId);
case "invitees": case "invitees":
return handleInvitees(referralRequest, request, authToken.getUser().getId()); return handleInvitees(referralRequest, request, userId);
} }
return null; return null;
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -11,17 +12,17 @@ import ru.soune.nocopy.dto.*;
import ru.soune.nocopy.dto.register.RegAnswer; import ru.soune.nocopy.dto.register.RegAnswer;
import ru.soune.nocopy.dto.register.RegRequest; import ru.soune.nocopy.dto.register.RegRequest;
import ru.soune.nocopy.entity.referral.Referral; import ru.soune.nocopy.entity.referral.Referral;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.EmailVerificationToken; import ru.soune.nocopy.entity.user.EmailVerificationToken;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.CompanyAlreadyExist; import ru.soune.nocopy.exception.CompanyAlreadyExist;
import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.exception.ValidationException; import ru.soune.nocopy.exception.ValidationException;
import ru.soune.nocopy.handler.validator.RegRequestValidator; import ru.soune.nocopy.handler.validator.RegRequestValidator;
import ru.soune.nocopy.repository.ReferralJpaRepository; import ru.soune.nocopy.repository.ReferralJpaRepository;
import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.mail.EmailService; import ru.soune.nocopy.service.mail.EmailService;
import ru.soune.nocopy.service.user.AdditionalInfoService; import ru.soune.nocopy.service.user.AdditionalInfoService;
import ru.soune.nocopy.service.user.UserService;
import ru.soune.nocopy.util.JwtUtil;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
@@ -30,12 +31,10 @@ import java.util.Map;
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class RegRequestHandler implements RequestHandler { public class RegRequestHandler implements RequestHandler {
private final UserRepository userRepository; private final UserService userService;
private final RegRequestValidator regRequestValidator; private final RegRequestValidator regRequestValidator;
private final AuthService authService;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final EmailService emailService; private final EmailService emailService;
@@ -46,11 +45,15 @@ public class RegRequestHandler implements RequestHandler {
private final AdditionalInfoService additionalInfoService; private final AdditionalInfoService additionalInfoService;
private final JwtUtil jwtUtil;
private final HttpServletRequest httpServletRequest;
@Override @Override
public BaseResponse handle(BaseRequest request) throws ValidationException { public BaseResponse handle(BaseRequest request) throws ValidationException {
RegRequest regRequest = objectMapper.convertValue(request.getMessageBody(), RegRequest.class); RegRequest regRequest = objectMapper.convertValue(request.getMessageBody(), RegRequest.class);
try { try {
if (userRepository.existsByEmail(regRequest.getEmail()) || userRepository.existsByPhone(regRequest.getPhone())) { if (userService.existsByEmailOrPhone(regRequest.getEmail(), regRequest.getPhone())) {
RegAnswer regAnswer = new RegAnswer(); RegAnswer regAnswer = new RegAnswer();
regAnswer.setFieldErrors(Arrays.asList(Map.of("email", regRequest.getEmail()))); regAnswer.setFieldErrors(Arrays.asList(Map.of("email", regRequest.getEmail())));
regAnswer.setFieldErrors(Arrays.asList(Map.of("phone", regRequest.getPhone()))); regAnswer.setFieldErrors(Arrays.asList(Map.of("phone", regRequest.getPhone())));
@@ -92,14 +95,16 @@ public class RegRequestHandler implements RequestHandler {
} }
boolean verified = mailVerified.equals("true"); boolean verified = mailVerified.equals("true");
Long createrId = (Long) httpServletRequest.getAttribute("userId");
AuthToken authToken = authService.register(regRequest, verified); User user = userService.createUser(regRequest, verified, createrId);
EmailVerificationToken emailToken = emailService.createEmailVerificationToken(authToken);
EmailVerificationToken emailToken = emailService.createEmailVerificationToken(user);
RegAnswer regAnswer = new RegAnswer(); RegAnswer regAnswer = new RegAnswer();
if (verified) { if (verified) {
try { try {
emailService.sendVerificationEmail(authToken.getUser(), emailToken.getToken()); emailService.sendVerificationEmail(user, emailToken.getToken());
} catch (Exception e) { } catch (Exception e) {
return new BaseResponse(request.getMsgId(), MessageCode.SEND_EMAIL_EXCEPTION.getCode(), return new BaseResponse(request.getMsgId(), MessageCode.SEND_EMAIL_EXCEPTION.getCode(),
MessageCode.SEND_EMAIL_EXCEPTION.getDescription(), Map.of( MessageCode.SEND_EMAIL_EXCEPTION.getDescription(), Map.of(
@@ -111,23 +116,22 @@ public class RegRequestHandler implements RequestHandler {
regAnswer.setVerified(false); regAnswer.setVerified(false);
regAnswer.setActive(false); regAnswer.setActive(false);
} else { } else {
regAnswer.setUserId(authToken.getUser().getId()); regAnswer.setUserId(user.getId());
regAnswer.setVerified(true); regAnswer.setVerified(true);
regAnswer.setActive(true); regAnswer.setActive(true);
} }
String token = authToken.getToken(); String token = jwtUtil.generateToken(user.getId(), user.getEmail());
authService.useUserAuthToken(token);
regAnswer.setToken(token); regAnswer.setToken(token);
regAnswer.setUserId(authToken.getUser().getId()); regAnswer.setUserId(user.getId());
if (regRequest.getAccountType().equals("b2c")) { if (regRequest.getAccountType().equals("b2c")) {
referralService.onRegister(authToken.getUser().getId(), regRequest.getReferralLink()); referralService.onRegister(user.getId(), regRequest.getReferralLink());
} }
additionalInfoService.additionalInfo(regRequest.getIp(), regRequest.getUserAgent(), authToken.getUser()); additionalInfoService.additionalInfo(regRequest.getIp(), regRequest.getUserAgent(), user);
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(), regAnswer); MessageCode.SUCCESS.getDescription(), regAnswer);
@@ -11,21 +11,16 @@ import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.file.ActionResponse; import ru.soune.nocopy.dto.file.ActionResponse;
import ru.soune.nocopy.dto.register.ResetPasswordRequest; import ru.soune.nocopy.dto.register.ResetPasswordRequest;
import ru.soune.nocopy.dto.register.ResetPasswordResponse; import ru.soune.nocopy.dto.register.ResetPasswordResponse;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.EmailVerificationToken; import ru.soune.nocopy.entity.user.EmailVerificationToken;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.exception.UserNotFoundException; import ru.soune.nocopy.exception.UserNotFoundException;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.repository.EmailVerificationTokenRepository; import ru.soune.nocopy.repository.EmailVerificationTokenRepository;
import ru.soune.nocopy.repository.UserRepository; import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.mail.EmailService; import ru.soune.nocopy.service.mail.EmailService;
import ru.soune.nocopy.service.register.AuthService; import ru.soune.nocopy.util.JwtUtil;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
@Component @Component
@Slf4j @Slf4j
@@ -36,35 +31,33 @@ public class ResetPasswordHandler implements RequestHandler{
private final EmailService emailService; private final EmailService emailService;
private final AuthService authService;
private final UserRepository userRepository; private final UserRepository userRepository;
private final EmailVerificationTokenRepository emailVerificationTokenRepository; private final EmailVerificationTokenRepository emailVerificationTokenRepository;
private final AuthTokenRepository authTokenRepository;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final JwtUtil jwtUtil;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
ResetPasswordRequest resetPasswordRequest = objectMapper.convertValue(request.getMessageBody(), ResetPasswordRequest resetPasswordRequest = objectMapper.convertValue(request.getMessageBody(),
ResetPasswordRequest.class); ResetPasswordRequest.class);
String action = resetPasswordRequest.getAction(); String action = resetPasswordRequest.getAction();
User user = userRepository.findByEmail(resetPasswordRequest.getEmail()); User user = userRepository.findByEmail(resetPasswordRequest.getEmail());
AuthToken authToken;
if (user == null) { if (user == null) {
throw new UserNotFoundException("User not found with email: " + resetPasswordRequest.getEmail()); throw new UserNotFoundException("User not found with email: " + resetPasswordRequest.getEmail());
} }
String authToken;
switch (action) { switch (action) {
case "resetPassword": case "resetPassword":
authToken = authService.generateAuthToken(user); authToken = jwtUtil.generateToken(user.getId(), user.getEmail());
EmailVerificationToken emailToken = emailService.createEmailVerificationToken(authToken); EmailVerificationToken emailToken = emailService.createEmailVerificationToken(user);
emailService.sendResetPasswordEmail(authToken.getUser(), emailToken.getToken()); emailService.sendResetPasswordEmail(user, emailToken.getToken());
return successResponse(request, authToken, user, MessageCode.SUCCESS.getDescription()); return successResponse(request, authToken, user, MessageCode.SUCCESS.getDescription());
case "confirmVerification": case "confirmVerification":
@@ -78,9 +71,7 @@ public class ResetPasswordHandler implements RequestHandler{
MessageCode.INVALID_TOKEN.getDescription(), Map.of("verifyToken", verifyToken)); MessageCode.INVALID_TOKEN.getDescription(), Map.of("verifyToken", verifyToken));
} }
List<AuthToken> authTokens = authTokenRepository.findByUserId(user.getId()); authToken = jwtUtil.generateToken(user.getId(), user.getEmail());
authToken = authTokens.isEmpty() ? authService.generateAuthToken(user): authTokens.getFirst();
user.setPassword(passwordEncoder.encode(resetPasswordRequest.getPassword())); user.setPassword(passwordEncoder.encode(resetPasswordRequest.getPassword()));
user.setActive(true); user.setActive(true);
@@ -102,9 +93,9 @@ public class ResetPasswordHandler implements RequestHandler{
} }
} }
private BaseResponse successResponse(BaseRequest request, AuthToken authToken, User user, String message) { private BaseResponse successResponse(BaseRequest request, String authToken, User user, String message) {
ResetPasswordResponse resetPasswordResponse = new ResetPasswordResponse(); ResetPasswordResponse resetPasswordResponse = new ResetPasswordResponse();
resetPasswordResponse.setAuthToken(authToken.getToken()); resetPasswordResponse.setAuthToken(authToken);
resetPasswordResponse.setUserId(user.getId()); resetPasswordResponse.setUserId(user.getId());
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), message, resetPasswordResponse); return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), message, resetPasswordResponse);
@@ -0,0 +1,34 @@
package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.complaint.ComplaintRequest;
import ru.soune.nocopy.dto.statistic.ComplaintStatisticResponse;
import ru.soune.nocopy.service.statistic.ComplaintStatisticService;
@Component
@RequiredArgsConstructor
@Slf4j
public class StatisticComplaintHandler implements RequestHandler {
private final ComplaintStatisticService complaintStatisticService;
private final ObjectMapper objectMapper;
@Override
public BaseResponse handle(BaseRequest request) throws Exception {
ComplaintRequest complaintRequest = objectMapper.convertValue(request.getMessageBody(), ComplaintRequest.class);
ComplaintStatisticResponse complaintStatisticResponse = complaintStatisticService.complaintStatistic(complaintRequest);
return new BaseResponse(
request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
complaintStatisticResponse);
}
}
@@ -1,6 +1,5 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -15,7 +14,6 @@ import ru.soune.nocopy.service.statistic.ViolationStatisticService;
@Slf4j @Slf4j
public class StatisticViolationHandler implements RequestHandler { public class StatisticViolationHandler implements RequestHandler {
private final ObjectMapper objectMapper;
private final ViolationStatisticService statisticService; private final ViolationStatisticService statisticService;
@Override @Override
@@ -0,0 +1,117 @@
package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.tarriff.TariffDTO;
import ru.soune.nocopy.dto.tarriff.TariffRequest;
import ru.soune.nocopy.dto.tarriff.TariffResponse;
import ru.soune.nocopy.entity.tarif.Tariff;
import ru.soune.nocopy.entity.tarif.TariffTimeTerm;
import ru.soune.nocopy.service.tariff.TariffService;
import java.util.List;
import java.util.Map;
@RequiredArgsConstructor
@Component
@Slf4j
public class TariffControlHandler implements RequestHandler {
private final ObjectMapper objectMapper;
private final TariffService tariffService;
@Override
public BaseResponse handle(BaseRequest request) throws Exception {
try {
TariffRequest tariffRequest = objectMapper.convertValue(request.getMessageBody(), TariffRequest.class);
String action = tariffRequest.getAction();
switch (action) {
case "add":
return handleAddTariff(request, tariffRequest);
case "remove":
return handleRemoveTariff(request, tariffRequest);
case "update":
return handleUpdateTariff(request, tariffRequest);
}
} catch (Exception e) {
log.error("Error add tariff", e);
return new BaseResponse(
request.getMsgId(),
MessageCode.SUCCESS.getCode(),
"Error processing request: " + e.getMessage(),
null);
}
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(), null);
}
private BaseResponse handleAddTariff(BaseRequest request, TariffRequest tariffRequest) {
tariffService.addTariff(tariffRequest.getName(), tariffRequest.getPrice(), tariffRequest.getType(),
tariffRequest.getTokens(), tariffRequest.getDiskSize(), tariffRequest.getMaxUsers(),
tariffRequest.getMaxFilesCount(), tariffRequest.getTariffTerm(), tariffRequest.getDescription(),
tariffRequest.getAccountType());
TariffResponse tariffResponse = TariffResponse.builder()
.tariffName(tariffRequest.getName())
.tariffType(tariffRequest.getType())
.build();
return new BaseResponse(request.getMsgId(), MessageCode.TARIFF_IS_ADD.getCode(),
MessageCode.TARIFF_IS_ADD.getDescription(),
tariffResponse);
}
private BaseResponse handleRemoveTariff(BaseRequest request, TariffRequest tariffRequest) {
TariffDTO tariff = tariffService.getTariffById(tariffRequest.getId());
if (tariff == null) {
return new BaseResponse(request.getMsgId(), MessageCode.TARIFF_IS_NOT_FOUND.getCode(),
MessageCode.TARIFF_IS_NOT_FOUND.getDescription(),
Map.of("id", tariffRequest.getId()));
}
TariffResponse tariffResponse = TariffResponse.builder()
.tariffName(tariff.getName())
.tariffType(tariff.getType())
.build();
if (tariffService.existTariffInfoByTariffId(tariffRequest.getId())) {
return new BaseResponse(request.getMsgId(), MessageCode.TARIFF_IS_NOT_DELETED.getCode(),
MessageCode.TARIFF_IS_NOT_DELETED.getDescription(),
tariffResponse);
}
tariffService.deleteTariff(tariffRequest.getId());
return new BaseResponse(request.getMsgId(), MessageCode.TARIFF_IS_DELETED.getCode(),
MessageCode.TARIFF_IS_DELETED.getDescription(),
tariffResponse);
}
private BaseResponse handleUpdateTariff(BaseRequest request, TariffRequest tariffRequest) {
TariffDTO tariff = tariffService.getTariffById(tariffRequest.getId());
if (tariff == null) {
return new BaseResponse(request.getMsgId(), MessageCode.TARIFF_IS_NOT_FOUND.getCode(),
MessageCode.TARIFF_IS_NOT_FOUND.getDescription(),
Map.of("id", tariffRequest.getId()));
}
TariffDTO tariffDTO = tariffService.updateTariff(tariffRequest.getId(), tariff, tariffRequest);
TariffResponse tariffResponse = TariffResponse.builder()
.tariffs(List.of(tariffDTO))
.build();
return new BaseResponse(request.getMsgId(), MessageCode.TARIFF_IS_UPDATED.getCode(),
MessageCode.TARIFF_IS_UPDATED.getDescription(),
tariffResponse);
}
}
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -15,6 +16,7 @@ import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.repository.AuthTokenRepository; import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.service.tariff.TariffService; import ru.soune.nocopy.service.tariff.TariffService;
import ru.soune.nocopy.service.user.UserService;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -28,7 +30,9 @@ public class TariffHandler implements RequestHandler {
private final TariffService tariffService; private final TariffService tariffService;
private final AuthTokenRepository authTokenRepository; private final UserService userService;
private final HttpServletRequest httpServletRequest;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
@@ -65,7 +69,8 @@ public class TariffHandler implements RequestHandler {
private BaseResponse handleAddTariff(BaseRequest request, TariffRequest tariffRequest) { private BaseResponse handleAddTariff(BaseRequest request, TariffRequest tariffRequest) {
tariffService.addTariff(tariffRequest.getName(), tariffRequest.getPrice(), tariffRequest.getType(), tariffService.addTariff(tariffRequest.getName(), tariffRequest.getPrice(), tariffRequest.getType(),
tariffRequest.getTokens(), tariffRequest.getDiskSize(), tariffRequest.getMaxUsers(), tariffRequest.getTokens(), tariffRequest.getDiskSize(), tariffRequest.getMaxUsers(),
tariffRequest.getMaxFilesCount(), tariffRequest.getTariffTerm()); tariffRequest.getMaxFilesCount(), tariffRequest.getTariffTerm(), tariffRequest.getDescription(),
tariffRequest.getAccountType());
TariffResponse tariffResponse = TariffResponse.builder() TariffResponse tariffResponse = TariffResponse.builder()
.tariffName(tariffRequest.getName()) .tariffName(tariffRequest.getName())
@@ -91,6 +96,12 @@ public class TariffHandler implements RequestHandler {
.tariffType(tariff.getType()) .tariffType(tariff.getType())
.build(); .build();
if (tariffService.existTariffInfoByTariffId(tariffRequest.getId())) {
return new BaseResponse(request.getMsgId(), MessageCode.TARIFF_IS_NOT_DELETED.getCode(),
MessageCode.TARIFF_IS_NOT_DELETED.getDescription(),
tariffResponse);
}
tariffService.deleteTariff(tariffRequest.getId()); tariffService.deleteTariff(tariffRequest.getId());
return new BaseResponse(request.getMsgId(), MessageCode.TARIFF_IS_DELETED.getCode(), return new BaseResponse(request.getMsgId(), MessageCode.TARIFF_IS_DELETED.getCode(),
@@ -107,7 +118,7 @@ public class TariffHandler implements RequestHandler {
Map.of("id", tariffRequest.getId())); Map.of("id", tariffRequest.getId()));
} }
TariffDTO tariffDTO = tariffService.updateTariff(tariffRequest.getId(), tariff); TariffDTO tariffDTO = tariffService.updateTariff(tariffRequest.getId(), tariff, tariffRequest);
TariffResponse tariffResponse = TariffResponse.builder() TariffResponse tariffResponse = TariffResponse.builder()
.tariffName(tariffDTO.getName()) .tariffName(tariffDTO.getName())
@@ -121,8 +132,16 @@ public class TariffHandler implements RequestHandler {
} }
private BaseResponse handleGetTariffs(BaseRequest request, TariffRequest tariffRequest) { private BaseResponse handleGetTariffs(BaseRequest request, TariffRequest tariffRequest) {
AuthToken authToken = authTokenRepository.findByToken(tariffRequest.getUserToken()).orElseThrow(); Long userId = (Long) httpServletRequest.getAttribute("userId");
User user = authToken.getUser(); User user = userService.getUserById(userId).orElse(null);
if (user == null) {
return new BaseResponse(
request.getMsgId(),
MessageCode.USER_NOT_FOUND.getCode(),
MessageCode.USER_NOT_FOUND.getDescription(),
Map.of("User:", userId));
}
if (tariffRequest.getTariffTerm() == null || !TariffTimeTerm.validTerms().contains( if (tariffRequest.getTariffTerm() == null || !TariffTimeTerm.validTerms().contains(
tariffRequest.getTariffTerm())) { tariffRequest.getTariffTerm())) {
@@ -20,7 +20,6 @@ import ru.soune.nocopy.service.tariff.TariffInfoService;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Component @Component
@@ -75,7 +74,7 @@ public class TariffInfoHandler implements RequestHandler {
private BaseResponse handleCreateTariffInfo(BaseRequest request, TariffInfoRequest tariffInfoRequest) { private BaseResponse handleCreateTariffInfo(BaseRequest request, TariffInfoRequest tariffInfoRequest) {
try { try {
Long tariffId = tariffInfoRequest.getTariffId(); Long tariffId = tariffInfoRequest.getTariffId();
Tariff tariff= tariffRepository.findById(tariffId).orElseThrow(); Tariff tariff = tariffRepository.findById(tariffId).orElseThrow();
TariffTimeTerm tariffTerm = tariff.getTariffTerm(); TariffTimeTerm tariffTerm = tariff.getTariffTerm();
LocalDateTime endDateTime = LocalDateTime.now().plusDays(tariffTerm.getDays()); LocalDateTime endDateTime = LocalDateTime.now().plusDays(tariffTerm.getDays());
@@ -0,0 +1,130 @@
package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.tarriff.TariffDTO;
import ru.soune.nocopy.dto.tarriff.TariffRequest;
import ru.soune.nocopy.dto.tarriff.TariffResponse;
import ru.soune.nocopy.entity.tarif.Tariff;
import ru.soune.nocopy.entity.tarif.TariffTimeTerm;
import ru.soune.nocopy.service.tariff.TariffService;
import java.util.List;
@RequiredArgsConstructor
@Component
@Slf4j
public class TariffInformationHandler implements RequestHandler {
private final ObjectMapper objectMapper;
private final TariffService tariffService;
@Override
public BaseResponse handle(BaseRequest request) throws Exception {
try {
TariffRequest tariffRequest = objectMapper.convertValue(request.getMessageBody(), TariffRequest.class);
String action = tariffRequest.getAction();
switch (action) {
case "get_all" :
return handleGetTariffs(request, tariffRequest);
case "tariffs_by_type" :
return handleGetTariffsByType(request, tariffRequest);
}
} catch (Exception e) {
log.error("Error add tariff", e);
return new BaseResponse(
request.getMsgId(),
MessageCode.SUCCESS.getCode(),
"Error processing request: " + e.getMessage(),
null);
}
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(), null);
}
private BaseResponse handleGetTariffsByType(BaseRequest request, TariffRequest req) {
int page = req.getPage() != null ? req.getPage() : 0;
int pageSize = req.getSize() != null ? req.getSize() : 5;
String sortDirection = req.getSortDirection() != null ? req.getSortDirection() : "desc";
String sortBy = req.getSortBy() != null ? req.getSortBy() : "name";
Pageable pageable = PageRequest.of(page, pageSize, Sort.by(Sort.Direction.fromString(sortDirection), sortBy));
Page<Tariff> allTariffs = tariffService.getTariffs(pageable);
List<TariffDTO> tariffDTOS = allTariffs.stream()
.map(this::convertToDTO)
.toList();
TariffResponse tariffResponse = TariffResponse.builder()
.tariffs(tariffDTOS)
.page(page)
.pageSize(pageSize)
.sortBy(sortBy)
.sortDirection(sortDirection)
.totalElements(allTariffs.getTotalElements())
.totalPages(allTariffs.getTotalPages())
.build();
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(), tariffResponse);
}
private BaseResponse handleGetTariffs(BaseRequest request, TariffRequest req) {
int page = req.getPage() != null ? req.getPage() : 0;
int pageSize = req.getSize() != null ? req.getSize() : 5;
String sortDirection = req.getSortDirection() != null ? req.getSortDirection() : "desc";
String sortBy = req.getSortBy() != null ? req.getSortBy() : "name";
Pageable pageable = PageRequest.of(page, pageSize, Sort.by(Sort.Direction.fromString(sortDirection), sortBy));
Page<Tariff> allTariffs = tariffService.getTariffs(pageable);
List<TariffDTO> tariffDTOS = allTariffs.stream()
.map(this::convertToDTO)
.toList();
TariffResponse tariffResponse = TariffResponse.builder()
.tariffs(tariffDTOS)
.page(page)
.pageSize(pageSize)
.sortBy(sortBy)
.sortDirection(sortDirection)
.totalElements(allTariffs.getTotalElements())
.totalPages(allTariffs.getTotalPages())
.build();
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(), tariffResponse);
}
private TariffDTO convertToDTO(Tariff tariff) {
TariffTimeTerm tariffTerm = tariff.getTariffTerm();
return new TariffDTO(
tariff.getId(),
tariff.getType(),
tariff.getName(),
tariff.getPrice(),
tariff.getTokens(),
tariff.getMaxFilesCount(),
tariff.getDiskSize(),
tariff.getMaxUsers(),
tariffTerm == null ? "" : tariffTerm.name(),
tariff.getDescription() == null ? "" : tariff.getDescription()
);
}
}
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -12,7 +13,6 @@ import ru.soune.nocopy.dto.tokenoperation.TokenOperationPageDto;
import ru.soune.nocopy.dto.tokenoperation.TokenOperationRequest; import ru.soune.nocopy.dto.tokenoperation.TokenOperationRequest;
import ru.soune.nocopy.entity.tokenoperation.OperationType; import ru.soune.nocopy.entity.tokenoperation.OperationType;
import ru.soune.nocopy.entity.tokenoperation.TokenOperation; import ru.soune.nocopy.entity.tokenoperation.TokenOperation;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.tokenoperation.TokenOperationService; import ru.soune.nocopy.service.tokenoperation.TokenOperationService;
import java.util.HashMap; import java.util.HashMap;
@@ -26,7 +26,7 @@ public class TokenOperationHandler implements RequestHandler {
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final AuthService authService; private final HttpServletRequest httpServletRequest;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
@@ -91,16 +91,7 @@ public class TokenOperationHandler implements RequestHandler {
} }
private BaseResponse handleGetList(Integer msgId, TokenOperationRequest request) { private BaseResponse handleGetList(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) { Long userId = (Long) httpServletRequest.getAttribute("userId");
return new BaseResponse(
msgId,
MessageCode.USER_NOT_FOUND.getCode(),
MessageCode.USER_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
try { try {
Page<TokenOperation> page = tokenOperationService.findByUserId( Page<TokenOperation> page = tokenOperationService.findByUserId(
@@ -189,16 +180,7 @@ public class TokenOperationHandler implements RequestHandler {
} }
private BaseResponse handleCreate(Integer msgId, TokenOperationRequest request) { private BaseResponse handleCreate(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) { Long userId = (Long) httpServletRequest.getAttribute("userId");
return new BaseResponse(
msgId,
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
try { try {
TokenOperation operation = tokenOperationService.create( TokenOperation operation = tokenOperationService.create(
@@ -316,16 +298,7 @@ public class TokenOperationHandler implements RequestHandler {
} }
private BaseResponse handleDeleteAllByUser(Integer msgId, TokenOperationRequest request) { private BaseResponse handleDeleteAllByUser(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) { Long userId = (Long) httpServletRequest.getAttribute("userId");
return new BaseResponse(
msgId,
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
try { try {
tokenOperationService.deleteByUserId(userId); tokenOperationService.deleteByUserId(userId);
@@ -350,16 +323,7 @@ public class TokenOperationHandler implements RequestHandler {
} }
private BaseResponse handleGetStats(Integer msgId, TokenOperationRequest request) { private BaseResponse handleGetStats(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) { Long userId = (Long) httpServletRequest.getAttribute("userId");
return new BaseResponse(
msgId,
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
if (userId == null) { if (userId == null) {
return new BaseResponse( return new BaseResponse(
@@ -405,16 +369,7 @@ public class TokenOperationHandler implements RequestHandler {
} }
private BaseResponse handleFilter(Integer msgId, TokenOperationRequest request) { private BaseResponse handleFilter(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) { Long userId = (Long) httpServletRequest.getAttribute("userId");
return new BaseResponse(
msgId,
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
try { try {
Page<TokenOperation> page = tokenOperationService.findByFilters( Page<TokenOperation> page = tokenOperationService.findByFilters(
@@ -3,6 +3,11 @@ package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest; import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.BaseResponse;
@@ -10,13 +15,20 @@ import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.user.UserAdditionalInfoBody; import ru.soune.nocopy.dto.user.UserAdditionalInfoBody;
import ru.soune.nocopy.dto.user.UserDTO;
import ru.soune.nocopy.entity.tarif.TariffInfo;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.entity.user.UserAdditionalInfo; import ru.soune.nocopy.entity.user.UserAdditionalInfo;
import ru.soune.nocopy.entity.user.UserAdditionalInfoAnswer; import ru.soune.nocopy.entity.user.UserAdditionalInfoAnswer;
import ru.soune.nocopy.entity.user.UserAdditionalInfoListAnswer; import ru.soune.nocopy.entity.user.UserAdditionalInfoListAnswer;
import ru.soune.nocopy.exception.UserAdditionalInfoNotFound; import ru.soune.nocopy.exception.UserAdditionalInfoNotFound;
import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.user.AdditionalInfoService; import ru.soune.nocopy.service.user.AdditionalInfoService;
import ru.soune.nocopy.service.user.UserService;
import ru.soune.nocopy.service.user.UserSpecifications;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@@ -28,8 +40,13 @@ import java.util.stream.Collectors;
public class UserInfoHandler implements RequestHandler { public class UserInfoHandler implements RequestHandler {
private final AdditionalInfoService additionalInfoService; private final AdditionalInfoService additionalInfoService;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final UserRepository userRepository;
private final UserService userService;
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
try { try {
@@ -40,15 +57,17 @@ public class UserInfoHandler implements RequestHandler {
return switch (body.getAction()) { return switch (body.getAction()) {
case "getAll" -> getAllAdditionalInfos(request); case "getAll" -> getAllAdditionalInfos(request);
case "getAllWithPagination" -> getAllAdditionalInfoWithPagination(request, body);
case "getById" -> getAdditionalInfoById(request, body.getUserId()); case "getById" -> getAdditionalInfoById(request, body.getUserId());
case "getIngoById" -> getInfoById(request, body.getUserId());
case "update" -> updateAdditionalInfo(request, body); case "update" -> updateAdditionalInfo(request, body);
case "delete" -> deleteAdditionalInfo(request, body.getUserId()); case "delete" -> deleteAdditionalInfo(request, body.getUserId());
default -> new BaseResponse( default -> new BaseResponse(
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_ACTION.getCode(), MessageCode.INVALID_ACTION.getCode(),
"Invalid action: " + body.getAction(), "Invalid action: " + body.getAction(),
null "valid actions: " + List.of("getAll", "getAllWithPagination", "getById",
); "getIngoById", "update", "delete"));
}; };
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
log.error("Validation error in UserInfoHandler", e); log.error("Validation error in UserInfoHandler", e);
@@ -96,6 +115,81 @@ public class UserInfoHandler implements RequestHandler {
); );
} }
private BaseResponse getAllAdditionalInfoWithPagination(BaseRequest request, UserAdditionalInfoBody req) {
Sort.Direction direction =
Sort.Direction.fromString(req.getSortDirection() != null ? req.getSortDirection() : "desc");
String sortBy = req.getSortBy() != null ? req.getSortBy() : "createdAt";
String sortField = switch (sortBy) {
case "fullName" -> "fullName";
case "email" -> "email";
case "createdAt" -> "createdAt";
case "verificationStatus" -> "verificationStatus";
case "tariff" -> "personalTariffInfo.status";
case "tokens" -> "personalTariffInfo.tokens";
default -> "createdAt";
};
Pageable pageable = PageRequest.of(req.getPage(), req.getSize(), Sort.by(direction, sortField));
Specification<User> spec = (root, query, cb) -> cb.conjunction();
if (req.getFullName() != null) {
spec = spec.and(UserSpecifications.byFullName(req.getFullName()));
}
if (req.getEmail() != null) {
spec = spec.and(UserSpecifications.byEmail(req.getEmail()));
}
if (req.getIsActive() != null) {
spec = spec.and(UserSpecifications.byIsActive(req.getIsActive()));
}
if (req.getEmailVerified() != null) {
spec = spec.and(UserSpecifications.byEmailVerified(req.getEmailVerified()));
}
if (req.getSubscriptionType() != null) {
spec = spec.and(UserSpecifications.bySubscriptionType(req.getSubscriptionType()));
}
if (req.getDateFrom() != null || req.getDateTo() != null) {
spec = spec.and(UserSpecifications.byCreatedAtRange(req.getDateFrom(), req.getDateTo()));
}
Page<User> allUsers = userRepository.findAll(spec, pageable);
Page<Map<String, Object>> dtoPage = allUsers.map(user -> {
Map<String, Object> map = new LinkedHashMap<>();
map.put("id", user.getId());
map.put("fullName", user.getFullName());
map.put("email", user.getEmail());
map.put("verificationStatus", user.getVerificationStatus() != null ? user.getVerificationStatus().name() : null);
map.put("createdAt", user.getCreatedAt() != null ? user.getCreatedAt().toString() : null);
TariffInfo tariff = user.getActiveTariffInfo();
if (tariff != null) {
map.put("tariff", tariff.getStatus() != null ? tariff.getStatus().name() : null);
map.put("tokens", tariff.getTokens() != null ? tariff.getTokens() : 0);
} else {
map.put("tariff", null);
map.put("tokens", 0);
}
return map;
});
Map<String, Object> response = new LinkedHashMap<>();
response.put("content", dtoPage.getContent());
response.put("totalElements", allUsers.getTotalElements());
response.put("totalPages", allUsers.getTotalPages());
response.put("number", allUsers.getNumber());
response.put("size", allUsers.getSize());
return new BaseResponse(
request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
response);
}
private BaseResponse getAdditionalInfoById(BaseRequest request, Long userId) { private BaseResponse getAdditionalInfoById(BaseRequest request, Long userId) {
log.info("Getting additional info for user: {}", userId); log.info("Getting additional info for user: {}", userId);
@@ -121,6 +215,22 @@ public class UserInfoHandler implements RequestHandler {
); );
} }
private BaseResponse getInfoById(BaseRequest request, Long userId) {
log.info("Getting info for user: {}", userId);
if (userId == null) {
throw new IllegalArgumentException("User Id is required for getById action");
}
UserDTO userInfo = userService.getUserInfo(userId);
return new BaseResponse(
request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
userInfo);
}
private BaseResponse updateAdditionalInfo(BaseRequest request, UserAdditionalInfoBody body) { private BaseResponse updateAdditionalInfo(BaseRequest request, UserAdditionalInfoBody body) {
log.info("Updating additional info for user: {}", body.getUserId()); log.info("Updating additional info for user: {}", body.getUserId());
@@ -1,21 +1,25 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest; import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.complaint.ComplaintRequest;
import ru.soune.nocopy.dto.file.ActionResponse; import ru.soune.nocopy.dto.file.ActionResponse;
import ru.soune.nocopy.dto.user.moderation.UserVerificationRequest; import ru.soune.nocopy.dto.user.moderation.UserVerificationRequest;
import ru.soune.nocopy.dto.user.moderation.UserVerificationResponse; import ru.soune.nocopy.dto.user.moderation.UserVerificationResponse;
import ru.soune.nocopy.entity.complaint.ComplaintEntity;
import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.entity.notification.NotificationType;
import ru.soune.nocopy.entity.user.ModerationStatus; import ru.soune.nocopy.entity.user.ModerationStatus;
import ru.soune.nocopy.entity.user.moderation.UserVerification; import ru.soune.nocopy.entity.user.moderation.UserVerification;
import ru.soune.nocopy.service.notification.NotificationService; import ru.soune.nocopy.service.notification.NotificationService;
import ru.soune.nocopy.service.user.moderation.UserVerificationService; import ru.soune.nocopy.service.user.moderation.UserVerificationService;
import java.time.format.DateTimeFormatter;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -81,10 +85,7 @@ public class UserVerificationHandler implements RequestHandler {
null); null);
} }
NotificationType notificationType = userVerification.getModerationStatus() == ModerationStatus.VERIFIED? addComplaintNotification(userVerification);
NotificationType.USER_VERIFIED: NotificationType.USER_NOT_VERIFIED;
notificationService.addNotification(notificationType, userVerification.getUserId());
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
@@ -95,6 +96,18 @@ public class UserVerificationHandler implements RequestHandler {
.build(); .build();
} }
private void addComplaintNotification(UserVerification userVerification) {
NotificationType notificationType = userVerification.getModerationStatus() == ModerationStatus.VERIFIED ?
NotificationType.USER_VERIFIED: NotificationType.USER_NOT_VERIFIED;
ObjectMapper mapper = new ObjectMapper();
ObjectNode context = mapper.createObjectNode();
context.put("status", userVerification.getModerationStatus().name());
context.put("update_date",
userVerification.getUpdatedAt().format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")));
notificationService.addNotification(notificationType, userVerification.getUserId(), context.toString());
}
private UserVerificationResponse convertDto(UserVerification userVerification) { private UserVerificationResponse convertDto(UserVerification userVerification) {
return UserVerificationResponse.builder() return UserVerificationResponse.builder()
@@ -10,22 +10,18 @@ import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.register.RegAnswer; import ru.soune.nocopy.dto.register.RegAnswer;
import ru.soune.nocopy.dto.register.VerifyUserRequest; import ru.soune.nocopy.dto.register.VerifyUserRequest;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.EmailVerificationToken; import ru.soune.nocopy.entity.user.EmailVerificationToken;
import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.exception.UserNotFoundException; import ru.soune.nocopy.exception.UserNotFoundException;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.repository.EmailVerificationTokenRepository; import ru.soune.nocopy.repository.EmailVerificationTokenRepository;
import ru.soune.nocopy.repository.UserRepository; import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.mail.EmailService; import ru.soune.nocopy.service.mail.EmailService;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.user.UserService; import ru.soune.nocopy.service.user.UserService;
import ru.soune.nocopy.util.JwtUtil;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
@Component @Component
@Slf4j @Slf4j
@@ -41,9 +37,7 @@ public class VerifyRegisterUserHandler implements RequestHandler {
private final UserService userService; private final UserService userService;
private final AuthTokenRepository authTokenRepository; private final JwtUtil jwtUtil;
private final AuthService authService;
@Override @Override
public BaseResponse handle(BaseRequest request) throws MessagingException, IOException { public BaseResponse handle(BaseRequest request) throws MessagingException, IOException {
@@ -54,45 +48,37 @@ public class VerifyRegisterUserHandler implements RequestHandler {
User user = userRepository.findById(userId) User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("User not found with id: " + userId)); .orElseThrow(() -> new UserNotFoundException("User not found with id: " + userId));
List<AuthToken> userAuthTokens = authTokenRepository.findByUserId(userId);
AuthToken authToken = userAuthTokens.isEmpty() ? authService.generateAuthToken(user): userAuthTokens.getFirst();
if (verifyUserRequest.getResend() != null && verifyUserRequest.getResend() == 1) { if (verifyUserRequest.getResend() != null && verifyUserRequest.getResend() == 1) {
return handleResend(request, user, authToken); return handleResend(request, user);
} }
String authToken = jwtUtil.generateToken(user.getId(), user.getEmail());
return handleVerify(request, user, authToken, verifyUserRequest.getVerifyToken()); return handleVerify(request, user, authToken, verifyUserRequest.getVerifyToken());
} }
private BaseResponse handleResend(BaseRequest request, User user, AuthToken authToken) throws MessagingException, IOException { private BaseResponse handleResend(BaseRequest request, User user) throws MessagingException, IOException {
EmailVerificationToken token = emailVerificationTokenRepository.findByUserId(user.getId()); EmailVerificationToken token = emailVerificationTokenRepository.findByUserId(user.getId());
// if (token != null && !token.isExpired()) {
// emailService.sendVerificationEmail(user, token.getToken());
//
// log.info("Verification token resent for user {}", user.getEmail());
// return successResponse(request, authToken, "Verification code has been resent", false,
// false, user.getEmail());
// }
if (token != null) { if (token != null) {
emailVerificationTokenRepository.delete(token); emailVerificationTokenRepository.delete(token);
} }
EmailVerificationToken newToken = emailService.createEmailVerificationToken(authToken); EmailVerificationToken newToken = emailService.createEmailVerificationToken(user);
emailService.sendVerificationEmail(user, newToken.getToken()); emailService.sendVerificationEmail(user, newToken.getToken());
log.info("New verification token generated for user {}", user.getEmail()); log.info("New verification token generated for user {}", user.getEmail());
String authToken = jwtUtil.generateToken(user.getId(), user.getEmail());
return successResponse(request, authToken, "New verification code has been sent", return successResponse(request, authToken, "New verification code has been sent",
false, false, user.getEmail()); false, false, user.getEmail());
} }
private BaseResponse handleVerify(BaseRequest request, User user, AuthToken authToken, String providedToken) { private BaseResponse handleVerify(BaseRequest request, User user, String authToken, String providedToken) {
EmailVerificationToken token = emailVerificationTokenRepository.findByUserIdAndToken(user.getId(), providedToken); EmailVerificationToken token = emailVerificationTokenRepository.findByUserIdAndToken(user.getId(), providedToken);
@@ -110,10 +96,10 @@ public class VerifyRegisterUserHandler implements RequestHandler {
updateUser.isEmailVerified(), updateUser.getEmail()); updateUser.isEmailVerified(), updateUser.getEmail());
} }
private BaseResponse successResponse(BaseRequest request, AuthToken authToken, String message, boolean isActive, private BaseResponse successResponse(BaseRequest request, String authToken, String message, boolean isActive,
boolean isVerified, String email) { boolean isVerified, String email) {
RegAnswer regAnswer = new RegAnswer(); RegAnswer regAnswer = new RegAnswer();
regAnswer.setToken(authToken.getToken()); regAnswer.setToken(authToken);
regAnswer.setVerified(isVerified); regAnswer.setVerified(isVerified);
regAnswer.setActive(isActive); regAnswer.setActive(isActive);
regAnswer.setEmail(email); regAnswer.setEmail(email);
@@ -1,20 +1,23 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest; import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.violation.ViolationRequest; import ru.soune.nocopy.dto.violation.ViolationRequest;
import ru.soune.nocopy.dto.violation.ViolationResponse; import ru.soune.nocopy.dto.violation.ViolationResponse;
import ru.soune.nocopy.entity.file.FileEntity; import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.violation.Violation; import ru.soune.nocopy.entity.violation.Violation;
import ru.soune.nocopy.repository.FileEntityRepository; import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.service.complaint.ComplaintEntityService;
import ru.soune.nocopy.service.complaint.LawCaseService;
import ru.soune.nocopy.service.file.FileEntityService; import ru.soune.nocopy.service.file.FileEntityService;
import ru.soune.nocopy.service.geo.GeoCountryService; import ru.soune.nocopy.service.geo.GeoCountryService;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.violation.ViolationService; import ru.soune.nocopy.service.violation.ViolationService;
import ru.soune.nocopy.service.violation.ViolationStatus; import ru.soune.nocopy.service.violation.ViolationStatus;
@@ -25,6 +28,7 @@ import java.time.format.DateTimeParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
@Component @Component
@Slf4j @Slf4j
@@ -36,12 +40,16 @@ public class ViolationHandler implements RequestHandler {
private final FileEntityRepository fileRepository; private final FileEntityRepository fileRepository;
private final AuthService authService;
private final FileEntityService fileEntityService; private final FileEntityService fileEntityService;
private final GeoCountryService geoCountryService; private final GeoCountryService geoCountryService;
private final LawCaseService lawCaseService;
private final ComplaintEntityService complaintEntityService;
private final HttpServletRequest httpServletRequest;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override @Override
@@ -49,15 +57,23 @@ public class ViolationHandler implements RequestHandler {
ViolationRequest violationRequest = objectMapper.convertValue(request.getMessageBody(), ViolationRequest.class); ViolationRequest violationRequest = objectMapper.convertValue(request.getMessageBody(), ViolationRequest.class);
validateRequest(violationRequest); validateRequest(violationRequest);
Long userId = (Long) httpServletRequest.getAttribute("userId");
String token = violationRequest.getToken();
Long userId = authService.useUserAuthToken(token);
List<FileEntity> targetFiles; List<FileEntity> targetFiles;
if (violationRequest.getFileId() != null && !violationRequest.getFileId().isEmpty()) { if (violationRequest.getFileId() != null && !violationRequest.getFileId().isEmpty()) {
FileEntity file = fileRepository.findById(violationRequest.getFileId()) FileEntity file = fileRepository.findById(violationRequest.getFileId())
.orElseThrow(() -> new FileNotFoundException("File not found with id: " + violationRequest.getFileId())); .orElseThrow(() -> new FileNotFoundException("File not found with id: " + violationRequest.getFileId()));
if (!Objects.equals(file.getUserId(), userId)) {
return BaseResponse.builder()
.messageCode(MessageCode.USER_NOT_HAD_PERMISSION.getCode())
.messageDesc(MessageCode.USER_NOT_HAD_PERMISSION.getDescription())
.msgId(request.getMsgId())
.messageBody(Map.of("user_id", userId))
.build();
}
targetFiles = List.of(file); targetFiles = List.of(file);
} else { } else {
targetFiles = fileEntityService.getAllUserFiles(userId); targetFiles = fileEntityService.getAllUserFiles(userId);
@@ -69,16 +85,34 @@ public class ViolationHandler implements RequestHandler {
if (violationRequest.getStartDate() != null && violationRequest.getEndDate() != null) { if (violationRequest.getStartDate() != null && violationRequest.getEndDate() != null) {
startDate = parseDate(violationRequest.getStartDate()); startDate = parseDate(violationRequest.getStartDate());
endDate = parseDate(violationRequest.getEndDate()); endDate = parseDate(violationRequest.getEndDate());
if (endDate != null && !violationRequest.getEndDate().contains(" ")) {
endDate = endDate.withHour(23).withMinute(59).withSecond(59);
}
} }
if ("updateStatus".equals(violationRequest.getAction())) { if ("updateStatus".equals(violationRequest.getAction())) {
String status = violationRequest.getStatus(); String status = violationRequest.getStatus();
Long violationId = violationRequest.getViolationId(); Long violationId = violationRequest.getViolationId();
if (status.equals(ViolationStatus.NOT_OWNER_FILE.name()) &&
lawCaseService.fetchByViolationId(violationId) != null &&
complaintEntityService.fetchComplaintByViolation(violationId) != null) {
return BaseResponse.builder()
.messageCode(MessageCode.COMPLAINT_OR_LAW_CASE_IN_WORK.getCode())
.messageCode(MessageCode.COMPLAINT_OR_LAW_CASE_IN_WORK.getCode())
.msgId(request.getMsgId())
.messageBody(Map.of("status", status))
.build();
}
violationService.changeStatus(ViolationStatus.valueOf(status), violationId); violationService.changeStatus(ViolationStatus.valueOf(status), violationId);
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
.messageCode(MessageCode.SUCCESS.getCode())
.messageDesc(MessageCode.SUCCESS.getDescription())
.messageBody(Map.of("status", status)) .messageBody(Map.of("status", status))
.build(); .build();
} }
@@ -94,35 +128,48 @@ public class ViolationHandler implements RequestHandler {
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
.messageCode(MessageCode.SUCCESS.getCode())
.messageDesc(MessageCode.SUCCESS.getDescription())
.messageBody(groupedData) .messageBody(groupedData)
.build(); .build();
} else { } else {
Page<Violation> violationPage; Page<Violation> violationPage = violationService.getViolationsByFilesAndFilters(
targetFiles,
if (startDate != null && endDate != null) { startDate,
violationPage = violationService.getViolationsByFilesAndDateRange( endDate,
targetFiles, startDate, endDate, violationRequest.getStatus(),
violationRequest.getPage(), violationRequest.getSize(), violationRequest.getSortDirection() violationRequest.getPage(),
); violationRequest.getSize(),
} else if (violationRequest.getStatus() != null && !violationRequest.getStatus().isEmpty()) { violationRequest.getSortDirection());
violationPage = violationService.getViolationsByFilesAndStatus(
targetFiles, violationRequest.getStatus(),
violationRequest.getPage(), violationRequest.getSize(), violationRequest.getSortDirection()
);
} else {
violationPage = violationService.getViolationsByFiles(
targetFiles,
violationRequest.getPage(), violationRequest.getSize(), violationRequest.getSortDirection()
);
}
ViolationResponse.ViolationDto firstShowViolation = null;
List<Violation> content = violationPage.getContent(); List<Violation> content = violationPage.getContent();
List<ViolationResponse.ViolationDto> violationDtos = new ArrayList<>(); List<ViolationResponse.ViolationDto> violationDtos = new ArrayList<>();
if ("getByViolationId".equals(violationRequest.getAction())) {
Violation violation = violationService.getById(violationRequest.getViolationId());
if (violation != null) {
firstShowViolation = ViolationResponse.ViolationDto.fromEntity(violation);
violationDtos.add(firstShowViolation);
}
}
for (Violation violation : content) { for (Violation violation : content) {
if (firstShowViolation != null && Objects.equals(firstShowViolation.getId(), violation.getId())) continue;
String country;
String countryCode;
ViolationResponse.ViolationDto violationDto = ViolationResponse.ViolationDto.fromEntity(violation); ViolationResponse.ViolationDto violationDto = ViolationResponse.ViolationDto.fromEntity(violation);
violationDto.setCountry(geoCountryService.getCountryName(violation.getPageUrl())); try {
violationDto.setCountryCode(geoCountryService.getCountryCode(violation.getPageUrl())); country = geoCountryService.getCountryName(violation.getHost());
countryCode = geoCountryService.getCountryCode(violation.getHost());
} catch (Exception e) {
country = geoCountryService.getCountryName(violation.getUrl());
countryCode = geoCountryService.getCountryCode(violation.getUrl());
}
violationDto.setCountry(country);
violationDto.setCountryCode(countryCode);
violationDtos.add(violationDto); violationDtos.add(violationDto);
} }
@@ -140,6 +187,8 @@ public class ViolationHandler implements RequestHandler {
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
.messageBody(response) .messageBody(response)
.messageCode(MessageCode.SUCCESS.getCode())
.messageDesc(MessageCode.SUCCESS.getDescription())
.build(); .build();
} }
} }
@@ -1,6 +1,7 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -8,11 +9,9 @@ import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.violation.*; import ru.soune.nocopy.dto.violation.*;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.service.violation.ViolationNotionService; import ru.soune.nocopy.service.violation.ViolationNotionService;
import java.util.Optional; import java.util.List;
@Slf4j @Slf4j
@Component @Component
@@ -22,7 +21,7 @@ public class ViolationNotionHandler implements RequestHandler {
private final ViolationNotionService notionService; private final ViolationNotionService notionService;
private final AuthTokenRepository authTokenRepository; private final HttpServletRequest httpServletRequest;
@Override @Override
public BaseResponse handle(BaseRequest request) { public BaseResponse handle(BaseRequest request) {
@@ -30,24 +29,7 @@ public class ViolationNotionHandler implements RequestHandler {
ViolationNotionRequest notionRequest = objectMapper.convertValue( ViolationNotionRequest notionRequest = objectMapper.convertValue(
request.getMessageBody(), ViolationNotionRequest.class); request.getMessageBody(), ViolationNotionRequest.class);
if (notionRequest.getToken() == null) { Long userId = (Long) httpServletRequest.getAttribute("userId");
return new BaseResponse(
request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Token is required",
null);
}
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(notionRequest.getToken());
if (tokenOptional.isEmpty()) {
return new BaseResponse(
request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Invalid token",
null);
}
Long userId = tokenOptional.get().getUser().getId();
String action = notionRequest.getAction(); String action = notionRequest.getAction();
if (action == null || action.trim().isEmpty()) { if (action == null || action.trim().isEmpty()) {
@@ -55,7 +37,9 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_ACTION.getCode(), MessageCode.INVALID_ACTION.getCode(),
"Action is required", "Action is required",
null); List.of("get_notions", "get_notion",
"add_notion", "update_notion",
"delete_notion"));
} }
switch (action) { switch (action) {
@@ -74,7 +58,9 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_ACTION.getCode(), MessageCode.INVALID_ACTION.getCode(),
"Invalid action: " + action, "Invalid action: " + action,
null); List.of("get_notions", "get_notion",
"add_notion", "update_notion",
"delete_notion"));
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@@ -83,21 +69,21 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.VALIDATION_ERROR.getCode(), MessageCode.VALIDATION_ERROR.getCode(),
e.getMessage(), e.getMessage(),
null); "Validation error: " + e.getMessage());
} catch (SecurityException e) { } catch (SecurityException e) {
log.error("Security error: {}", e.getMessage()); log.error("Security error: {}", e.getMessage());
return new BaseResponse( return new BaseResponse(
request.getMsgId(), request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(), MessageCode.ACCESS_DENIED.getCode(),
e.getMessage(), e.getMessage(),
null); "Security error: " + e.getMessage());
} catch (Exception e) { } catch (Exception e) {
log.error("Unexpected error", e); log.error("Unexpected error", e);
return new BaseResponse( return new BaseResponse(
request.getMsgId(), request.getMsgId(),
MessageCode.INTERNAL_ERROR.getCode(), MessageCode.INTERNAL_ERROR.getCode(),
"Internal server error", "Internal server error",
null); "Unexpected error: " + e);
} }
} }
@@ -107,7 +93,7 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_JSON_BODY.getCode(), MessageCode.INVALID_JSON_BODY.getCode(),
"ViolationId is required for get_notions action", "ViolationId is required for get_notions action",
null); "field: violation_id");
} }
try { try {
@@ -116,13 +102,15 @@ public class ViolationNotionHandler implements RequestHandler {
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
.messageBody(notions) .messageBody(notions)
.messageDesc(MessageCode.SUCCESS.getDescription())
.messageCode(MessageCode.SUCCESS.getCode())
.build(); .build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return new BaseResponse( return new BaseResponse(
request.getMsgId(), request.getMsgId(),
MessageCode.NOTION_NOT_FOUND.getCode(), MessageCode.NOTION_NOT_FOUND.getCode(),
e.getMessage(), e.getMessage(),
null); "Unexpected error: " + e);
} }
} }
@@ -132,7 +120,7 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_JSON_BODY.getCode(), MessageCode.INVALID_JSON_BODY.getCode(),
"NotionId is required for get_notion action", "NotionId is required for get_notion action",
null); "field: notion_id");
} }
try { try {
@@ -141,13 +129,15 @@ public class ViolationNotionHandler implements RequestHandler {
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
.messageBody(notion) .messageBody(notion)
.messageDesc(MessageCode.SUCCESS.getDescription())
.messageCode(MessageCode.SUCCESS.getCode())
.build(); .build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return new BaseResponse( return new BaseResponse(
request.getMsgId(), request.getMsgId(),
MessageCode.NOTION_NOT_FOUND.getCode(), MessageCode.NOTION_NOT_FOUND.getCode(),
e.getMessage(), e.getMessage(),
null); "Unexpected error: " + e);
} }
} }
@@ -157,7 +147,7 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_JSON_BODY.getCode(), MessageCode.INVALID_JSON_BODY.getCode(),
"ViolationId is required for add_notion action", "ViolationId is required for add_notion action",
null); "field: notion_id");
} }
if (notionRequest.getMessage() == null || notionRequest.getMessage().trim().isEmpty()) { if (notionRequest.getMessage() == null || notionRequest.getMessage().trim().isEmpty()) {
@@ -165,7 +155,7 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_JSON_BODY.getCode(), MessageCode.INVALID_JSON_BODY.getCode(),
"Message is required for add_notion action", "Message is required for add_notion action",
null); "field: message");
} }
try { try {
@@ -174,13 +164,15 @@ public class ViolationNotionHandler implements RequestHandler {
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
.messageBody(created) .messageBody(created)
.messageDesc(MessageCode.SUCCESS.getDescription())
.messageCode(MessageCode.SUCCESS.getCode())
.build(); .build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return new BaseResponse( return new BaseResponse(
request.getMsgId(), request.getMsgId(),
MessageCode.NOTION_NOT_FOUND.getCode(), MessageCode.NOTION_NOT_FOUND.getCode(),
e.getMessage(), e.getMessage(),
null); "Unexpected error: " + e);
} }
} }
@@ -190,7 +182,7 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_JSON_BODY.getCode(), MessageCode.INVALID_JSON_BODY.getCode(),
"NotionId is required for update_notion action", "NotionId is required for update_notion action",
null); "field: notion_id");
} }
if (notionRequest.getMessage() == null || notionRequest.getMessage().trim().isEmpty()) { if (notionRequest.getMessage() == null || notionRequest.getMessage().trim().isEmpty()) {
@@ -198,7 +190,7 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_JSON_BODY.getCode(), MessageCode.INVALID_JSON_BODY.getCode(),
"Message is required for update_notion action", "Message is required for update_notion action",
null); "field: message");
} }
try { try {
@@ -207,19 +199,21 @@ public class ViolationNotionHandler implements RequestHandler {
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
.messageBody(updated) .messageBody(updated)
.messageDesc(MessageCode.SUCCESS.getDescription())
.messageCode(MessageCode.SUCCESS.getCode())
.build(); .build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return new BaseResponse( return new BaseResponse(
request.getMsgId(), request.getMsgId(),
MessageCode.NOTION_NOT_FOUND.getCode(), MessageCode.NOTION_NOT_FOUND.getCode(),
e.getMessage(), e.getMessage(),
null); "IllegalArgumentException error: " + e);
} catch (SecurityException e) { } catch (SecurityException e) {
return new BaseResponse( return new BaseResponse(
request.getMsgId(), request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(), MessageCode.ACCESS_DENIED.getCode(),
e.getMessage(), e.getMessage(),
null); "SecurityException error: " + e);
} }
} }
@@ -229,7 +223,7 @@ public class ViolationNotionHandler implements RequestHandler {
request.getMsgId(), request.getMsgId(),
MessageCode.INVALID_JSON_BODY.getCode(), MessageCode.INVALID_JSON_BODY.getCode(),
"NotionId is required for delete_notion action", "NotionId is required for delete_notion action",
null); "field: notion_id");
} }
try { try {
@@ -239,9 +233,12 @@ public class ViolationNotionHandler implements RequestHandler {
.message("Notion deleted successfully") .message("Notion deleted successfully")
.deleted(true) .deleted(true)
.build(); .build();
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
.messageBody(deleteResponse) .messageBody(deleteResponse)
.messageDesc(MessageCode.SUCCESS.getDescription())
.messageCode(MessageCode.SUCCESS.getCode())
.build(); .build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return new BaseResponse( return new BaseResponse(
@@ -1,21 +1,22 @@
package ru.soune.nocopy.handler; package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest; import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.violation.ViolationStatisticsRequest; import ru.soune.nocopy.dto.violation.ViolationStatisticsRequest;
import ru.soune.nocopy.dto.violation.ViolationStatisticsResponse; import ru.soune.nocopy.dto.violation.ViolationStatisticsResponse;
import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.exception.FileEntityNotFoundException;
import ru.soune.nocopy.repository.AuthTokenRepository; import ru.soune.nocopy.exception.UserNotHavePermission;
import ru.soune.nocopy.service.violation.ViolationService; import ru.soune.nocopy.service.violation.ViolationService;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.util.Optional;
@Slf4j @Slf4j
@Component @Component
@@ -25,16 +26,14 @@ public class ViolationStatisticsHandler implements RequestHandler {
private final ViolationService violationService; private final ViolationService violationService;
private final AuthTokenRepository authTokenRepository; private final HttpServletRequest httpServletRequest;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override @Override
public BaseResponse handle(BaseRequest request) throws Exception { public BaseResponse handle(BaseRequest request) throws Exception {
ViolationStatisticsRequest statRequest = objectMapper.convertValue( ViolationStatisticsRequest statRequest = objectMapper.convertValue(request.getMessageBody(),
request.getMessageBody(), ViolationStatisticsRequest.class); ViolationStatisticsRequest.class);
validateRequest(statRequest);
LocalDateTime startDate = null; LocalDateTime startDate = null;
LocalDateTime endDate = null; LocalDateTime endDate = null;
@@ -48,33 +47,40 @@ public class ViolationStatisticsHandler implements RequestHandler {
} }
} }
Optional<AuthToken> tokenOptional = Long userId = (Long) httpServletRequest.getAttribute("userId");
authTokenRepository.findByToken(statRequest.getToken()); ViolationStatisticsResponse statistics;
if (tokenOptional.isEmpty()) { try {
throw new IllegalArgumentException("User token is required"); statistics = violationService.getViolationStatistics(
userId,
statRequest.getFileId(),
startDate,
endDate);
} catch (UserNotHavePermission e) {
return BaseResponse.builder()
.msgId(request.getMsgId())
.messageBody("userId: " + userId)
.messageCode(MessageCode.USER_NOT_HAD_PERMISSION.getCode())
.messageDesc(MessageCode.USER_NOT_HAD_PERMISSION.getDescription())
.build();
} catch (FileEntityNotFoundException e) {
return BaseResponse.builder()
.msgId(request.getMsgId())
.messageBody("fileId: " + statRequest.getFileId())
.messageDesc(MessageCode.FILE_NOT_FOUND.getDescription())
.messageCode(MessageCode.FILE_NOT_FOUND.getCode())
.build();
} }
Long userId = tokenOptional.orElseThrow().getUser().getId();
ViolationStatisticsResponse statistics = violationService.getViolationStatistics(
userId,
statRequest.getFileId(),
startDate,
endDate);
return BaseResponse.builder() return BaseResponse.builder()
.msgId(request.getMsgId()) .msgId(request.getMsgId())
.messageBody(statistics) .messageBody(statistics)
.messageCode(MessageCode.SUCCESS.getCode())
.messageDesc(MessageCode.SUCCESS.getDescription())
.build(); .build();
} }
private void validateRequest(ViolationStatisticsRequest request) {
if (request.getToken() == null) {
throw new IllegalArgumentException("Token is required");
}
}
private LocalDateTime parseDate(String dateStr) { private LocalDateTime parseDate(String dateStr) {
try { try {
return LocalDateTime.parse(dateStr, DATE_FORMATTER); return LocalDateTime.parse(dateStr, DATE_FORMATTER);
@@ -84,8 +84,4 @@ public class FileUploadRequestValidator implements Validator {
"Invalid file type. Valid types: " + Arrays.toString(FileType.values())); "Invalid file type. Valid types: " + Arrays.toString(FileType.values()));
} }
} }
private String getFileExtension(String fileName) {
return fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
}
} }
@@ -0,0 +1,119 @@
package ru.soune.nocopy.migration;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.service.file.cloud.CloudStorageService;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
@Component
@Slf4j
@RequiredArgsConstructor
public class S3MigrationTool {
private final FileEntityRepository fileEntityRepository;
private final CloudStorageService cloudStorageService;
private static final Path FAILED_LOG = Paths.get("migration_failed.txt");
public void migrationFilesToS3() {
log.info("=== START MIGRATION ===");
clearLogFile();
List<FileEntity> allFiles = fileEntityRepository.findAll();
log.info("Total files: {}", allFiles.size());
int success = 0;
List<String> failedIds = new ArrayList<>();
for (FileEntity file : allFiles) {
if (migrateFile(file)) {
success++;
} else {
failedIds.add(file.getId());
}
}
log.info("=== COMPLETED: success {}, failed {} ===", success, failedIds.size());
if (!failedIds.isEmpty()) {
log.info("Failed file IDs: {}", String.join(", ", failedIds));
log.info("Details saved to: {}", FAILED_LOG.toAbsolutePath());
}
}
private boolean migrateFile(FileEntity file) {
StringBuilder errors = new StringBuilder();
try {
cloudStorageService.saveFilesToStorage(
file.getMimeType(), file.getFileExtension(), file.getFilePath()
);
} catch (Exception e) {
errors.append("main:").append(e.getMessage()).append("; ");
}
if ("image".equals(file.getMimeType())) {
try {
cloudStorageService.saveFilesToStorage(
file.getMimeType(), file.getFileExtension(), file.getMediumPath()
);
} catch (Exception e) {
errors.append("medium:").append(e.getMessage()).append("; ");
}
try {
cloudStorageService.saveFilesToStorage(
file.getMimeType(), file.getFileExtension(), file.getThumbnailPath()
);
} catch (Exception e) {
errors.append("thumb:").append(e.getMessage()).append("; ");
}
}
if (file.getProtectedFilePath() != null) {
try {
cloudStorageService.saveFilesToStorage(
file.getMimeType() != null ? file.getMimeType() : "application",
file.getFileExtension(),
file.getProtectedFilePath()
);
} catch (Exception e) {
errors.append("protected:").append(e.getMessage()).append("; ");
}
}
if (errors.length() > 0) {
writeToFile(String.format("%s | %s | %s",
file.getId(), file.getOriginalFileName(), errors));
log.warn("Failed to migrate: {} | {}", file.getId(), file.getOriginalFileName());
return false;
}
return true;
}
private void clearLogFile() {
try {
Files.deleteIfExists(FAILED_LOG);
} catch (IOException e) {
log.warn("Failed to clear log file");
}
}
private void writeToFile(String line) {
try {
Files.write(FAILED_LOG, (line + "\n").getBytes(),
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
} catch (IOException e) {
log.error("Failed to write to log file", e);
}
}
}
@@ -5,11 +5,13 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import ru.soune.nocopy.entity.complaint.ComplaintEntity; import ru.soune.nocopy.entity.complaint.ComplaintEntity;
import ru.soune.nocopy.entity.complaint.ComplaintStatus; import ru.soune.nocopy.entity.complaint.ComplaintStatus;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -18,7 +20,9 @@ public interface ComplaintEntityRepository extends JpaRepository<ComplaintEntity
Optional<ComplaintEntity> findById(Long id); Optional<ComplaintEntity> findById(Long id);
Page<ComplaintEntity> findAll(Pageable pageable); Page<ComplaintEntity> findAll(Pageable pageable);
Page<ComplaintEntity> findByStatus(ComplaintStatus status, Pageable pageable); Page<ComplaintEntity> findByStatus(ComplaintStatus status, Pageable pageable);
List<ComplaintEntity> findByViolationId(Long violationId); ComplaintEntity findByViolationId(Long violationId);
@Query("SELECT c FROM ComplaintEntity c WHERE c.violation.id = :violationId AND c.status IN :statuses")
List<ComplaintEntity> findByViolationIdAndStatuses(@Param("violationId") Long violationId, @Param("statuses") List<String> statuses);
boolean existsByViolationId(Long violationId); boolean existsByViolationId(Long violationId);
@Modifying @Modifying
@@ -29,6 +33,9 @@ public interface ComplaintEntityRepository extends JpaRepository<ComplaintEntity
@Query("SELECT COUNT(c.id) FROM ComplaintEntity c") @Query("SELECT COUNT(c.id) FROM ComplaintEntity c")
Long getTotalComplaintsCount(); Long getTotalComplaintsCount();
@Query("SELECT COUNT(c.id) FROM ComplaintEntity c WHERE c.status = :status")
Long getTotalComplaintsCountByStatus(@Param("status")ComplaintStatus status);
@Query(""" @Query("""
SELECT COUNT(c.id) SELECT COUNT(c.id)
FROM ComplaintEntity c FROM ComplaintEntity c
@@ -37,4 +44,12 @@ public interface ComplaintEntityRepository extends JpaRepository<ComplaintEntity
) )
""") """)
Long getComplaintsWithoutLawCaseCount(); Long getComplaintsWithoutLawCaseCount();
Long countComplaintEntityByEmailAndCreatedAtBetween(String email, LocalDateTime startDate, LocalDateTime endDate);
@Query("SELECT COUNT(c) FROM ComplaintEntity c WHERE c.violation.id IN :violations")
Long countComplaintByViolations(@Param("violations") List<Long> violations);
@Query("SELECT c FROM ComplaintEntity c WHERE c.email IN :emails")
Page<ComplaintEntity> getComplaintsByUserEmails(@Param("emails") List<String> emails, Pageable pageable);
} }
@@ -0,0 +1,103 @@
package ru.soune.nocopy.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import ru.soune.nocopy.entity.docviewer.DockView;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Repository
public interface DockViewRepository extends JpaRepository<DockView, Long> {
List<DockView> findAllByFileId(String fileId);
@Query("SELECT d.viewerIp FROM DockView d WHERE d.fileId IN :fileIds")
List<String> findAllViewerIps(@Param("fileIds") List<String> fileIds);
List<DockView> findAllByViewerId(Long viewerId);
Optional<DockView> findByFileIdAndViewerId(String fileId, Long viewerId);
List<DockView> findAllByViewerIp(String viewerIp);
Page<DockView> findAllByFileIdOrderByCreatedAtDesc(String fileId, Pageable pageable);
@Query("SELECT dv FROM DockView dv WHERE dv.fileId IN :fileIds")
Page<DockView> findAllByFileIds(@Param("fileIds") List<String> fileIds, Pageable pageable);
@Query("SELECT " +
"COUNT(dv) as totalViews, " +
"COUNT(DISTINCT dv.viewerIp) as uniqueIps, " +
"COUNT(DISTINCT dv.viewerId) as uniqueUsers, " +
"MAX(dv.createdAt) as lastViewDate, " +
"MIN(dv.createdAt) as firstViewDate " +
"FROM DockView dv " +
"WHERE dv.fileId IN :fileIds")
List<Object[]> findTotalViewsStatsByFileIds(@Param("fileIds") List<String> fileIds);
Page<DockView> findAllByViewerIdOrderByCreatedAtDesc(Long viewerId, Pageable pageable);
long countByFileId(String fileId);
@Query("SELECT COUNT(DISTINCT dv.viewerIp) FROM DockView dv WHERE dv.fileId = :fileId")
long countUniqueIpsByFileId(@Param("fileId") String fileId);
@Query("SELECT COUNT(DISTINCT dv.viewerId) FROM DockView dv WHERE dv.fileId = :fileId")
long countUniqueViewersByFileId(@Param("fileId") String fileId);
@Query("SELECT MAX(dv.createdAt) FROM DockView dv WHERE dv.fileId = :fileId")
Optional<LocalDateTime> findLastViewDateByFileId(@Param("fileId") String fileId);
@Query("SELECT dv.fileId, " +
"COUNT(dv) as totalViews, " +
"COUNT(DISTINCT dv.viewerIp) as uniqueIps, " +
"MAX(dv.createdAt) as lastViewDate " +
"FROM DockView dv " +
"GROUP BY dv.fileId " +
"ORDER BY lastViewDate DESC")
Page<Object[]> findViewsStatsPaginated(Pageable pageable);
@Query("SELECT dv.fileId, " +
"COUNT(dv) as totalViews, " +
"COUNT(DISTINCT dv.viewerIp) as uniqueIps, " +
"COUNT(DISTINCT dv.viewerId) as uniqueUsers, " +
"MAX(dv.createdAt) as lastViewDate, " +
"MIN(dv.createdAt) as firstViewDate " +
"FROM DockView dv " +
"WHERE dv.fileId = :fileId " +
"GROUP BY dv.fileId")
Optional<Object[]> findViewsStatsByFileId(@Param("fileId") String fileId);
@Query("SELECT dv.fileId, " +
"COUNT(dv) as totalViews, " +
"COUNT(DISTINCT dv.viewerIp) as uniqueIps, " +
"COUNT(DISTINCT dv.viewerId) as uniqueUsers, " +
"MAX(dv.createdAt) as lastViewDate, " +
"MIN(dv.createdAt) as firstViewDate " +
"FROM DockView dv " +
"WHERE dv.fileId IN :fileIds " +
"GROUP BY dv.fileId")
List<Object[]> findViewsStatsByFileIds(@Param("fileIds") List<String> fileIds);
void deleteAllByFileId(String fileId);
void deleteAllByCreatedAtBefore(LocalDateTime date);
List<DockView> findAllByFileIdAndCreatedAtBetween(
String fileId,
LocalDateTime startDate,
LocalDateTime endDate
);
boolean existsByFileIdAndViewerIp(String fileId, String viewerIp);
List<DockView> findTop10ByFileIdOrderByCreatedAtDesc(String fileId);
}

Some files were not shown because too many files have changed in this diff Show More