367 Commits

Author SHA1 Message Date
Paulo Gustavo Veiga
2c9a181496 Update springboot version. 2024-05-21 20:02:35 -07:00
Paulo Gustavo Veiga
82d5caa1ea Merge branch 'develop' of github.com:wisemapping/wisemapping-open-source into develop 2024-04-06 08:45:28 -07:00
Paulo Gustavo Veiga
c71da91af0 Improve application.yml documentation. 2024-04-06 08:43:20 -07:00
Paulo Gustavo Veiga
a89a4ff049 Update README.md 2024-04-06 02:58:12 -07:00
Paulo Gustavo Veiga
20f730eb36 Update README.md 2024-04-06 02:56:54 -07:00
Paulo Gustavo Veiga
ec7dd972b6 Update README.md 2024-04-06 02:53:39 -07:00
Paulo Gustavo Veiga
0d3d28b871 Minor change 2024-04-06 02:52:44 -07:00
Paulo Gustavo Veiga
b04baef6e9 Minor fix. 2024-04-06 02:51:10 -07:00
Paulo Gustavo Veiga
b510e4929e Improve documentation. 2024-04-06 02:47:01 -07:00
Paulo Gustavo Veiga
12b46b4400 Update springboot version. 2024-03-25 23:59:02 -07:00
Paulo Gustavo Veiga
0d7b66a54f Update springboot. 2024-03-25 23:53:10 -07:00
Paulo Gustavo Veiga
cfb2fc60d8 Minor fix on metadata permissions. 2024-03-25 22:47:37 -07:00
Paulo Gustavo Veiga
4401cf8fe9 Fix metadata endpoint permissions. 2024-03-25 22:45:21 -07:00
Paulo Gustavo Veiga
21dfcf3c4f Add missing endpoint on non-auth. 2024-03-25 22:40:35 -07:00
Paulo Gustavo Veiga
8b583bf5b2 Fix logo image. 2024-03-25 22:29:15 -07:00
Paulo Gustavo Veiga
b821e96e13 Fix failing test 2024-03-24 19:04:52 -07:00
Paulo Gustavo Veiga
eb66e6981a Fix docker base api 2024-03-24 11:19:09 -07:00
Paulo Gustavo Veiga
efc3cd5753 Add build docker image. 2024-03-24 11:13:31 -07:00
Paulo Gustavo Veiga
8ca83bfdad Remove dependecy analyzer 2024-03-24 11:08:38 -07:00
Paulo Gustavo Veiga
39dbafa536 Skip test execution. 2024-03-24 11:05:43 -07:00
Paulo Gustavo Veiga
08339cb721 Update dependecy graph. 2024-03-24 11:03:54 -07:00
Paulo Gustavo Veiga
2847ef434c Add zulu as distribution. 2024-03-24 11:01:30 -07:00
Paulo Gustavo Veiga
9c2e8219af Update java version. 2024-03-24 10:56:03 -07:00
Paulo Gustavo Veiga
72acbc8d65 Update Java requirement. 2024-03-24 10:53:45 -07:00
Paulo Gustavo Veiga
28afb28241 Remove bitbucket build config. 2024-03-24 10:48:53 -07:00
Paulo Gustavo Veiga
b05df6f957 Fist version of CI/CD 2024-03-24 10:42:45 -07:00
Paulo Gustavo Veiga
9493e3addb Update java version. 2024-03-24 10:24:55 -07:00
Paulo Gustavo Veiga
c2ddbed929 Remove webapp. 2024-03-24 10:22:34 -07:00
Paulo Gustavo Veiga
3273d74501 Bump version. 2024-03-24 10:18:19 -07:00
Paulo Gustavo Veiga
c287d47c84 Merge branch 'feature/springboot2' into develop 2024-03-24 10:15:42 -07:00
Paulo Gustavo Veiga
1e548136ff Improve code. 2024-03-24 09:01:43 -07:00
Paulo Gustavo Veiga
ede2fb7622 Improve code. 2024-03-24 08:33:06 -07:00
Paulo Gustavo Veiga
e99424db01 Add code. 2024-03-24 00:37:14 -07:00
Paulo Gustavo Veiga
be27292699 Minor change. 2024-03-24 00:15:55 -07:00
Paulo Gustavo Veiga
0f4cfcd0d1 Add jwt token on confirmation. 2024-03-24 00:15:04 -07:00
Paulo Gustavo Veiga
3daebd149a Return token. 2024-03-23 23:29:48 -07:00
Paulo Gustavo Veiga
12d67d42ea Add login. 2024-03-23 23:07:14 -07:00
Paulo Gustavo Veiga
16e2829598 Add logs. 2024-03-23 22:56:12 -07:00
Paulo Gustavo Veiga
9547543042 Add missing auth. 2024-03-21 22:22:32 -07:00
Paulo Gustavo Veiga
cad9c6ca0f Fix endpoint URL 2024-03-21 22:16:31 -07:00
Paulo Gustavo Veiga
174c98a6a5 Add missing oath attribute 2024-03-21 22:00:18 -07:00
Paulo Gustavo Veiga
3c11f4034f Add ui base url. 2024-03-13 22:10:09 -07:00
Paulo Gustavo Veiga
c6af830dfa Update java vesion. 2024-03-13 21:56:29 -07:00
Paulo Gustavo Veiga
80ffdebf33 Update springboot. 2024-03-13 21:54:23 -07:00
Paulo Gustavo Veiga
002d761645 Remove docker. 2024-03-13 21:49:50 -07:00
Paulo Gustavo Veiga
33f228c30c Minor fix on email adrress on mail. 2024-03-13 21:22:23 -07:00
Paulo Gustavo Veiga
34acc83582 Improve error message. 2024-02-29 19:38:16 -08:00
Paulo Gustavo Veiga
d7ac0ec28f Fix test. 2024-02-20 22:13:43 -08:00
Paulo Gustavo Veiga
853f500454 Add JWT time. 2024-02-20 21:52:56 -08:00
Paulo Gustavo Veiga
849e700ef8 Minor fix, 2024-02-19 21:47:49 -08:00
Paulo Gustavo Veiga
08ce41da5f Add creator full name 2024-02-19 21:15:45 -08:00
Paulo Gustavo Veiga
cf154de2e4 Add new test. 2024-02-19 14:12:51 -08:00
Paulo Gustavo Veiga
2e20bd6a0e Add configuration endpoint. 2024-02-19 00:28:05 -08:00
Paulo Gustavo Veiga
fef33dad03 Add support for configuration. 2024-02-18 22:55:19 -08:00
Paulo Gustavo Veiga
af97d51cba Change mail image. 2024-02-18 18:37:39 -08:00
Paulo Gustavo Veiga
4c9af90815 Remove dead code. 2024-02-18 18:35:51 -08:00
Paulo Gustavo Veiga
aa75aefe66 Fix server props. 2024-02-18 16:20:22 -08:00
Paulo Gustavo Veiga
00935dbb93 Improve docker image. 2024-02-18 16:14:56 -08:00
Paulo Gustavo Veiga
b9bd733e5e Add missing corse. 2024-02-18 08:44:46 -08:00
Paulo Gustavo Veiga
e409abb265 Add headers on CORS 2024-02-17 19:32:53 -08:00
Paulo Gustavo Veiga
bf3b082bdf Webconfig. 2024-02-17 18:21:33 -08:00
Paulo Gustavo Veiga
3106b3e94a Add cors configuration support. 2024-02-17 18:16:46 -08:00
Paulo Gustavo Veiga
a829844c1a Test cors config. 2024-02-17 18:07:58 -08:00
Paulo Gustavo Veiga
7f959ce869 Add postgress suppot 2024-02-17 13:48:11 -08:00
Paulo Gustavo Veiga
52fdefb57e Fixed. 2024-02-17 11:18:43 -08:00
Paulo Gustavo Veiga
0dcdc2c263 Fix posgresql 2024-02-17 00:54:41 -08:00
Paulo Gustavo Veiga
aadb88451b Mysql 2024-02-17 00:14:09 -08:00
Paulo Gustavo Veiga
83e080d677 Update to MySQL 8. 2024-02-16 22:49:33 -08:00
Paulo Gustavo Veiga
b13748d47d Remove UI support 2024-02-16 22:20:28 -08:00
Paulo Gustavo Veiga
eaf03ea28d Clean up. 2024-02-11 12:21:38 -08:00
Paulo Gustavo Veiga
f8b8aea901 Add support for configure http basic. 2024-02-10 13:53:44 -08:00
Paulo Gustavo Veiga
6f528835bf Fix try access. 2024-02-09 23:55:05 -08:00
Paulo Gustavo Veiga
555c6383b9 Fix location resolver. 2024-02-09 23:35:26 -08:00
Paulo Gustavo Veiga
34318c1e3f Fix json props. 2024-02-09 00:02:56 -08:00
Paulo Gustavo Veiga
05c2e545ae Add map metadata. 2024-02-07 18:44:33 -08:00
Paulo Gustavo Veiga
885de4e1c1 Fix login bug. 2024-02-07 00:04:06 -08:00
Paulo Gustavo Veiga
56c322fd3f Add redirect on expiration. 2024-02-06 23:43:52 -08:00
Paulo Gustavo Veiga
e3998ef3d4 Migrate to springboot emai. 2024-02-06 23:04:25 -08:00
Paulo Gustavo Veiga
88d5f0df43 Renove http basic. 2024-02-06 22:26:44 -08:00
Paulo Gustavo Veiga
37d7a9bb6d Add missing expoint test. 2024-02-06 21:12:15 -08:00
Paulo Gustavo Veiga
d798358fec Minor expoint fixes. 2024-02-05 21:21:34 -08:00
Paulo Gustavo Veiga
96b6ff3841 Fix typo on path. 2024-02-04 21:10:48 -08:00
Paulo Gustavo Veiga
34a5328a2c Complete JWT token support. 2024-02-04 20:53:24 -08:00
Paulo Gustavo Veiga
082f2614e3 Move to in memory 2024-02-04 19:45:14 -08:00
Paulo Gustavo Veiga
069943cf30 Add first version of token generation. 2024-02-04 18:28:23 -08:00
Paulo Gustavo Veiga
6674c607f7 Add registration test. 2024-02-04 17:31:21 -08:00
Paulo Gustavo Veiga
a681cf9b90 Add user test. 2024-02-04 17:21:51 -08:00
Paulo Gustavo Veiga
9382fc2995 Clean up code. 2024-02-04 10:47:10 -08:00
Paulo Gustavo Veiga
af4016cadd Improve code on rest. 2024-02-04 10:42:16 -08:00
Paulo Gustavo Veiga
fdffda6186 Improve code. 2024-02-04 10:09:10 -08:00
Paulo Gustavo Veiga
d4c50b4c2a Remove MVC ui support. 2024-02-04 08:54:07 -08:00
Paulo Gustavo Veiga
b3ea3e5a5b Container load. 2024-02-04 08:45:00 -08:00
Paulo Gustavo Veiga
01e0639c55 Fix compose. 2024-02-03 23:22:38 -08:00
Paulo Gustavo Veiga
71f77f6e79 Start docker compoose. 2024-02-03 23:10:32 -08:00
Paulo Gustavo Veiga
f046bcaebc Start working on docker compose. 2024-02-03 20:35:09 -08:00
Paulo Gustavo Veiga
c976046fca Convert to yaml. 2024-02-03 19:42:15 -08:00
Paulo Gustavo Veiga
7724d9106d Clean up jpa setting. 2024-02-03 19:37:10 -08:00
Paulo Gustavo Veiga
f86f96a35e Test 100% 2024-02-03 15:35:09 -08:00
Paulo Gustavo Veiga
e28302236b Fix more test. 2024-02-03 15:27:26 -08:00
Paulo Gustavo Veiga
f528abaa44 Fix more tests. 2024-02-03 15:13:38 -08:00
Paulo Gustavo Veiga
80c30daece More tests fixed. 2024-02-03 14:51:59 -08:00
Paulo Gustavo Veiga
51e2732ae2 Fix more tests. 2024-02-03 14:17:30 -08:00
Paulo Gustavo Veiga
1db881e3e2 Fix more tests. 2024-02-03 12:26:18 -08:00
Paulo Gustavo Veiga
1059643b0f Fix label test. 2024-01-23 22:31:46 -08:00
Paulo Gustavo Veiga
740da238fa Fix test. 2024-01-23 22:20:10 -08:00
Paulo Gustavo Veiga
ccfcb3b335 fix more test 2024-01-22 23:18:25 -08:00
Paulo Gustavo Veiga
56e4970861 Fix more test. 2024-01-22 23:11:20 -08:00
Paulo Gustavo Veiga
861b4f22fd Improve security filter code. 2024-01-22 23:08:04 -08:00
Paulo Gustavo Veiga
cdbeaf5216 Fix more tests. 2024-01-22 22:46:38 -08:00
Paulo Gustavo Veiga
d49766463a Add automation. 2024-01-22 21:54:37 -08:00
Paulo Gustavo Veiga
27c310197e Remove. 2024-01-21 22:28:03 -08:00
Paulo Gustavo Veiga
bbb6f362bd Fix test. 2024-01-21 22:27:53 -08:00
Paulo Gustavo Veiga
6ca26ffd10 Fix test 2024-01-21 22:09:28 -08:00
Paulo Gustavo Veiga
a3022d36d2 Fix SQL data initialization 2024-01-21 22:02:58 -08:00
Paulo Gustavo Veiga
f0bc9e53ea Fix platform initialization 2024-01-21 17:39:14 -08:00
Paulo Gustavo Veiga
fc66a52232 More fixes 2024-01-21 17:36:56 -08:00
Paulo Gustavo Veiga
d03a9e5eea Fix controller loading. 2024-01-21 15:42:02 -08:00
Paulo Gustavo Veiga
50a0c340b2 Improve security filter code. 2024-01-21 15:18:07 -08:00
Paulo Gustavo Veiga
a3b289a738 Fix application config 2024-01-20 14:51:46 -08:00
Paulo Gustavo Veiga
9dcb139169 Clean up configuration 2024-01-16 21:24:21 -08:00
Paulo Gustavo Veiga
a69256b793 Fix classpath 2024-01-15 20:10:52 -08:00
Paulo Gustavo Veiga
33ec2de925 Fix more tests. 2024-01-15 18:13:57 -08:00
Paulo Gustavo Veiga
c99d7837a3 Remove icon as mandatory 2024-01-15 18:10:01 -08:00
Paulo Gustavo Veiga
2357101b42 Fix test 2024-01-15 18:09:01 -08:00
Paulo Gustavo Veiga
832e1991e5 Fix several tests 2024-01-15 17:30:31 -08:00
Paulo Gustavo Veiga
7d4f51b3ea Fix test 2024-01-15 16:47:28 -08:00
Paulo Gustavo Veiga
12832b0a91 Merge branch 'feature/springboot2' of bitbucket.org:wisemapping/wisemapping-open-source into feature/springboot2 2024-01-15 16:39:28 -08:00
Paulo Gustavo Veiga
c91cafa8ff Simplyfy auth. 2024-01-15 16:38:18 -08:00
Paulo Gustavo Veiga
a4c0c4deb7 Simplyfy auth. 2024-01-15 16:36:29 -08:00
Paulo Gustavo Veiga
b7591ab995 Fix authentication. 2024-01-15 16:20:00 -08:00
Paulo Gustavo Veiga
5fe3bb082a Fix interceptor 2024-01-15 15:42:04 -08:00
Paulo Gustavo Veiga
3a9aad02cf Partial migration of mail 2024-01-15 14:08:23 -08:00
Paulo Gustavo Veiga
03a6c0ef8b Fix rest auth. Review filters. 2024-01-15 07:59:04 -08:00
Paulo Gustavo Veiga
2f32ef66e9 Migrate all to entity manager. 2024-01-13 18:49:49 -08:00
Paulo Gustavo Veiga
fbbc95fd59 Fix JPA load. 2024-01-13 18:31:21 -08:00
Paulo Gustavo Veiga
e98d6ca2a9 Add missing properly on embedd view 2023-12-13 12:21:14 -08:00
Paulo Gustavo Veiga
712fbaa3a7 Handle authentication errors to avoid being reported as 500 2023-12-12 18:07:44 -08:00
Paulo Gustavo Veiga
19d083e218 Fix property lazy initialization error. 2023-12-04 20:29:19 -08:00
Paulo Gustavo Veiga
e1b517f657 Add db creation. 2023-12-04 20:00:06 -08:00
Paulo Gustavo Veiga
fa06852806 Add static resources. 2023-11-27 21:47:22 -08:00
Paulo Gustavo Veiga
079f8ac417 Fix MVC 2023-11-27 21:09:00 -08:00
Paulo Gustavo Veiga
ea6b2ad106 Fix public resource sharing. 2023-11-26 16:13:45 -08:00
Paulo Gustavo Veiga
52d684d611 Fix JPA. 2023-11-26 15:42:22 -08:00
Paulo Gustavo Veiga
c29098d717 WIP 2023-11-24 19:26:36 -08:00
Paulo Gustavo Veiga
15325672a0 Move db initialization to beans. 2023-11-22 21:43:11 -08:00
Paulo Gustavo Veiga
cd3d21f106 Move app.properties definition 2023-11-22 20:46:38 -08:00
Paulo Gustavo Veiga
12b0bb4866 Add missing message. 2023-11-22 20:29:10 -08:00
Paulo Gustavo Veiga
2c1e634a1a Fix log level for ValidationException 2023-11-22 20:23:52 -08:00
Paulo Gustavo Veiga
597e3ab165 Move security auth. 2023-11-22 16:50:56 -08:00
Paulo Gustavo Veiga
1c73a8d79d Fix exception handling on JSP 2023-11-20 19:56:28 -08:00
Paulo Gustavo Veiga
68c8f5c6b8 Add @Transactional to controller. 2023-11-20 19:47:53 -08:00
Paulo Gustavo Veiga
d26b516eb9 Clean up. 2023-11-20 19:44:59 -08:00
Paulo Gustavo Veiga
538083ae83 Add transction 2023-11-20 19:37:08 -08:00
Paulo Gustavo Veiga
60923e4c8b Improve error log. 2023-11-20 19:26:08 -08:00
Paulo Gustavo Veiga
214e3938c1 Add JSP comments. 2023-11-20 19:19:57 -08:00
Paulo Gustavo Veiga
f49ae37866 Add exception details in JSP. 2023-11-20 19:14:01 -08:00
Paulo Gustavo Veiga
ad158e4821 Fix parameter injection. 2023-11-20 18:57:50 -08:00
Paulo Gustavo Veiga
769968376b Add log verbosity. 2023-11-20 08:00:09 -08:00
Paulo Gustavo Veiga
9668823c31 Fix missing URLs. 2023-11-20 07:41:51 -08:00
Paulo Gustavo Veiga
55c104cfbe fix lazy initialization error. 2023-11-20 07:27:56 -08:00
Paulo Gustavo Veiga
92edef9bd6 Minor variable rename. 2023-11-19 20:28:27 -08:00
Paulo Gustavo Veiga
884a93478b Fix been lazy loading issue. 2023-11-19 20:22:05 -08:00
Paulo Gustavo Veiga
63975464ca Add enable_lazy_load_no_trans fix. 2023-11-19 19:11:06 -08:00
Paulo Gustavo Veiga
2b918a0df3 Move collaborations to header to prevent aused by org.hibernate.LazyInitializationException: could not initialize proxy [com.wisemapping.model.Collaborator#758998] - no Session error 2023-11-19 18:55:16 -08:00
Paulo Gustavo Veiga
9c1320b63b Fix logger path location. 2023-11-19 15:59:43 -08:00
Paulo Gustavo Veiga
1589665633 Move log4j2-stdout.xml 2023-11-19 15:56:59 -08:00
Paulo Gustavo Veiga
479eb6db2c Refactor beens loading. 2023-11-19 15:40:16 -08:00
Paulo Gustavo Veiga
a739bb3e0b Move more services out of XML definition. 2023-11-19 08:28:40 -08:00
Paulo Gustavo Veiga
50e4a68d28 More classes to annotation. 2023-11-19 08:05:38 -08:00
Paulo Gustavo Veiga
8ec7c4edea Move couple of classes to services
Improve label security.
2023-11-19 07:57:23 -08:00
Paulo Gustavo Veiga
480fd49fd0 Keep transaction simplication 2023-11-19 00:31:41 -08:00
Paulo Gustavo Veiga
61c691fc82 Fix creation. 2023-11-18 23:45:31 -08:00
Paulo Gustavo Veiga
3eaeb8f500 Fix new user creation. 2023-11-18 23:30:06 -08:00
Paulo Gustavo Veiga
07e8259417 WIP 2023-11-18 23:22:25 -08:00
Paulo Gustavo Veiga
ab15fb2d36 Fix lock message. 2023-11-15 20:45:15 -08:00
Paulo Veiga
315267e68c Migrate to hibernate 6 2023-10-30 05:34:45 +00:00
Paulo Veiga
881a16b908 messages_ru.properties edited online with Bitbucket 2023-10-09 23:39:25 +00:00
Paulo Veiga
dd8f5ab1ea README.md edited online with Bitbucket 2023-10-07 17:55:06 +00:00
Paulo Veiga
0c37ed904a license.md edited online with Bitbucket 2023-10-07 17:51:04 +00:00
Paulo Gustavo Veiga
946ef517d3 Merge branch 'develop' of bitbucket.org:wisemapping/wisemapping-open-source into develop 2023-10-07 10:44:57 -07:00
Paulo Gustavo Veiga
5116a18952 Add database configuration. 2023-10-07 10:44:12 -07:00
Paulo Veiga
3467114a8a README.md edited online with Bitbucket 2023-10-07 17:11:11 +00:00
Paulo Gustavo Veiga
cda97891ba Change format. 2023-10-07 10:07:26 -07:00
Paulo Gustavo Veiga
675802dab7 Remove public and try from index. 2023-08-29 20:14:14 -07:00
Paulo Gustavo Veiga
8b72f75b56 Bump up UI version. 2023-08-28 08:45:35 -07:00
Paulo Gustavo Veiga
e85a670695 Fix embedded view issue. 2023-08-23 08:15:39 -07:00
Paulo Gustavo Veiga
28dc77c501 Bump mail version. 2023-08-16 20:17:29 -07:00
Paulo Gustavo Veiga
c4ae51b50e Add missing dependency. 2023-08-16 19:35:56 -07:00
Paulo Gustavo Veiga
9912897879 Revert "Add mail provider."
This reverts commit 8d3983fd08.
2023-08-16 19:32:17 -07:00
Paulo Gustavo Veiga
8d3983fd08 Add mail provider. 2023-08-16 19:24:16 -07:00
Paulo Gustavo Veiga
169c6e6538 Improve security filters 2023-08-12 18:57:13 -07:00
Paulo Gustavo Veiga
4bb2960716 Increase default_batch_fetch_size 2023-08-11 18:28:50 -07:00
Paulo Gustavo Veiga
70c0b0c532 Update mysql driver. 2023-08-11 18:18:40 -07:00
Paulo Gustavo Veiga
0b96026507 Update tomcat version to 10.1.11-jdk17 2023-08-11 18:08:47 -07:00
Paulo Gustavo Veiga
87712b2493 Fix public map access. 2023-08-10 23:18:59 -07:00
Paulo Gustavo Veiga
c783feef65 Add flavicon on auth exclusion. 2023-08-10 22:46:48 -07:00
Paulo Gustavo Veiga
ea12d0246c Revert pipeline changes. 2023-08-10 22:30:54 -07:00
Paulo Gustavo Veiga
4f94d7117a Update pipeline docker image. 2023-08-10 21:57:27 -07:00
Paulo Gustavo Veiga
abcd0d8515 Add spring messages. 2023-08-10 21:42:03 -07:00
Paulo Gustavo Veiga
1742b268a9 Fix log level on docker image. 2023-08-10 21:34:11 -07:00
Paulo Gustavo Veiga
aaa8d5f0f3 Update tomcat version. 2023-08-10 21:27:37 -07:00
Paulo Gustavo Veiga
553688b070 Refactor variable properties. 2023-08-06 21:57:26 -07:00
Paulo Gustavo Veiga
d2788ae00e Fix logger 2023-08-06 21:51:07 -07:00
Paulo Gustavo Veiga
d4840b9c20 Fix logger 2023-08-06 21:48:10 -07:00
Paulo Gustavo Veiga
b8601d7029 Fix typo 2023-08-06 20:35:42 -07:00
Paulo Gustavo Veiga
86682ca7d8 Fix base closing tag. 2023-08-06 20:02:30 -07:00
Paulo Gustavo Veiga
762ebabe7e Define plugin version. 2023-08-06 17:34:27 -07:00
Paulo Gustavo Veiga
30b2e7e8eb Define compiler version. 2023-08-06 17:31:35 -07:00
Paulo Gustavo Veiga
5844663701 Merge branch 'develop' of bitbucket.org:wisemapping/wisemapping-open-source into develop 2023-08-01 22:17:15 -07:00
Paulo Veiga
55c5126d95 Merged feature/update_spring into develop
* Migrate authentication to beans.
* Fix test execution
* Update to java 17
* Fix failing tests.
* Fix java 17 migration warnings
* Move error page to react.
* Remove Tiles !!!!
* Fix hibernate warning
* Update to jslt 3.0.1
* Bump version.
2023-08-01 04:32:51 +00:00
Paulo Gustavo Veiga
734ec3df67 Bump version. 2023-07-31 21:31:56 -07:00
Paulo Gustavo Veiga
40afd70780 Update to jslt 3.0.1 2023-07-31 21:08:56 -07:00
Paulo Gustavo Veiga
4ebef65728 Fix hibernate warning 2023-07-30 22:50:04 -07:00
Paulo Gustavo Veiga
e55e7e8867 Remove Tiles !!!! 2023-07-30 22:34:31 -07:00
Paulo Gustavo Veiga
1340fff68a Move error page to react. 2023-07-30 22:31:24 -07:00
Paulo Gustavo Veiga
68aa7c20eb Fix java 17 migration warnings 2023-07-30 20:12:11 -07:00
Paulo Gustavo Veiga
963ed70d8d Fix failing tests. 2023-07-30 18:21:25 -07:00
Paulo Gustavo Veiga
0090464d88 Update to java 17 2023-07-30 18:04:45 -07:00
Paulo Gustavo Veiga
53173ec75d Fix test execution 2023-07-28 23:09:44 -07:00
Paulo Gustavo Veiga
a66dff8ae4 Migrate authentication to beans. 2023-07-28 22:46:38 -07:00
Mario Voigt
1d7633b65c Merged in Mario-Voigt/fix-german-translations-1689632224218 (pull request #23)
fix german translations

Approved-by: Paulo Veiga
2023-07-28 05:27:21 +00:00
Paulo Gustavo Veiga
f72b89d59a Update springboot version. 2023-07-02 11:03:19 -07:00
Paulo Gustavo Veiga
30098527b5 Enforce password size limit 2023-07-02 10:13:42 -07:00
Paulo Gustavo Veiga
ae633022ab Fix german translation. 2023-07-02 09:20:49 -07:00
Paulo Gustavo Veiga
6ff203f019 Fix missing resource errors. 2023-07-02 09:18:00 -07:00
Paulo Gustavo Veiga
87bd4bf182 Revert version tomcat 2023-06-29 20:27:33 -07:00
Paulo Gustavo Veiga
fb1de1fcca Update maven image version. 2023-06-29 20:16:25 -07:00
Paulo Gustavo Veiga
fd07ea6102 Update images. 2023-06-29 20:11:48 -07:00
Paulo Gustavo Veiga
046c2af947 Revert docket image publish 2023-06-29 19:46:28 -07:00
Paulo Gustavo Veiga
bb14c0d1c5 update maven-war-plugin fixed. 2023-06-29 18:09:40 -07:00
Paulo Gustavo Veiga
9871ad6843 Multi image generation. 2023-06-28 23:27:20 -07:00
Paulo Gustavo Veiga
33f9eae3cb Update maven-compiler-plugin version. 2023-06-28 23:11:48 -07:00
Paulo Gustavo Veiga
d918f210aa Update maven version. 2023-06-28 23:05:22 -07:00
Paulo Gustavo Veiga
fa6c0bac33 Multi image publish. 2023-06-28 22:33:40 -07:00
Paulo Gustavo Veiga
c41796a54b Fix public view render. 2023-04-06 18:38:49 -07:00
Paulo Gustavo Veiga
e3bcaec5de Fix missing public files on public view render. 2023-04-06 18:38:07 -07:00
Paulo Gustavo Veiga
c2bec7ca4a Revert "Update to tomcat 10.1.7"
This reverts commit 198038f110.
2023-04-01 18:03:04 -07:00
Paulo Gustavo Veiga
198038f110 Update to tomcat 10.1.7 2023-04-01 17:56:18 -07:00
Paulo Gustavo Veiga
df72b64e1b Update docker version. 2023-04-01 17:39:37 -07:00
Paulo Gustavo Veiga
1f59f26c07 Update tomcat version. 2023-04-01 17:35:05 -07:00
Paulo Gustavo Veiga
8c17b4bdcd Update tomcat base version. 2023-04-01 17:23:58 -07:00
Paulo Gustavo Veiga
c92ff3154f Update libraries version. 2023-04-01 16:56:29 -07:00
Paulo Gustavo Veiga
b1805f55b2 Set static distribution version for tomcat. 2023-04-01 16:18:45 -07:00
Paulo Gustavo Veiga
1379a593ae Revert "Revert spring lib update."
This reverts commit 4967a5b930.
2023-04-01 14:39:43 -07:00
Paulo Gustavo Veiga
4967a5b930 Revert spring lib update. 2023-04-01 14:10:51 -07:00
Paulo Gustavo Veiga
02ee11a094 Fix issue https://bitbucket.org/wisemapping/wisemapping-open-source/issues/18/mysql-create-schemassql-error 2023-04-01 13:42:07 -07:00
Paulo Gustavo Veiga
6acde03327 Improve OAuth error handling. 2023-04-01 13:33:15 -07:00
Paulo Gustavo Veiga
7918bc20d0 Improve german translation. 2023-04-01 11:18:00 -07:00
Paulo Gustavo Veiga
11ee64fcf1 Update package version. 2023-02-15 23:30:33 -08:00
Paulo Gustavo Veiga
ca27e37c4b Fix postgress support 2023-02-15 22:47:42 -08:00
Paulo Gustavo Veiga
917442f418 Change default mindmap theme 2023-02-15 19:09:53 -08:00
Paulo Gustavo Veiga
3f00b76bd6 Fix render. 2023-02-03 19:03:14 -08:00
Paulo Gustavo Veiga
0769a511b5 Fix non loading error. 2023-02-03 03:36:51 -08:00
Paulo Gustavo Veiga
c138f7b667 Fix header. 2023-01-31 16:31:54 -08:00
Paulo Gustavo Veiga
ef6d50b26d Support null value on map description. 2023-01-20 19:12:24 -08:00
Paulo Gustavo Veiga
439b237caa Fix adding harcode description. 2023-01-18 21:36:56 -08:00
Paulo Gustavo Veiga
39ff7622f3 Bump up version. 2023-01-02 19:49:07 -08:00
Paulo Gustavo Veiga
766de183eb Release 5.0.19 2023-01-02 19:43:54 -08:00
Paulo Gustavo Veiga
844a3768b0 Minor change. 2022-12-17 17:54:14 -08:00
Paulo Gustavo Veiga
16180f4c6d Minor refactor for oauth.:wq 2022-12-17 17:33:59 -08:00
Gustavo Fuhr
2592d338bb Google Authenticaition support 2022-12-13 02:36:58 +00:00
Paulo Gustavo Veiga
d88e655eee Add postgreSQL driver. 2022-12-05 20:07:35 -08:00
Paulo Gustavo Veiga
6205cba586 Remove ads from public view 2022-12-05 19:55:16 -08:00
Paulo Gustavo Veiga
7f6343bdc8 Load ads after 15 mil 2022-11-20 09:28:38 -08:00
Paulo Gustavo Veiga
ac3f4bed31 Change default font for view. 2022-11-20 07:46:02 -08:00
Paulo Gustavo Veiga
f6a8cbdf38 Optimize font loading. 2022-11-20 07:38:36 -08:00
Paulo Gustavo Veiga
b34eabc800 Specify script async load. 2022-11-20 00:52:19 -08:00
Paulo Gustavo Veiga
72368be54e Fix loading error. 2022-11-20 00:04:15 -08:00
Paulo Gustavo Veiga
da6feccc5b Fix page location. 2022-11-20 00:02:43 -08:00
Paulo Gustavo Veiga
5a79c1ef38 Fix accesiblity errors. 2022-11-20 00:01:16 -08:00
Paulo Gustavo Veiga
ea071562ca Fix zoom and center rendering. 2022-11-19 11:36:09 -08:00
Paulo Gustavo Veiga
4f701d0b74 Fix lighthouse usability errors. 2022-11-14 20:18:34 -08:00
Paulo Gustavo Veiga
34b00a8a7f Add missing password encodder object. 2022-11-12 14:12:19 -08:00
Paulo Gustavo Veiga
11dba85641 Update to tomcat 10 base image. 2022-10-27 22:47:21 -07:00
Paulo Gustavo Veiga
35d8e19c3c Revert "Revert "Update docker base image.""
This reverts commit 16ac1c468d.
2022-10-27 20:44:55 -07:00
Paulo Gustavo Veiga
16ac1c468d Revert "Update docker base image."
This reverts commit 52d6a12e0f.
2022-10-27 20:43:15 -07:00
Paulo Gustavo Veiga
52d6a12e0f Update docker base image. 2022-10-27 20:34:46 -07:00
Paulo Gustavo Veiga
23b0f7351e Resolve several critical vulnerabilities. 2022-10-27 20:28:37 -07:00
Paulo Gustavo Veiga
49732ec06d Update mysql driver version 2022-10-27 19:47:51 -07:00
Paulo Veiga
6c78eb078f Update JDBC drivers. 2022-10-28 02:07:39 +00:00
Paulo Veiga
17e04a6f3f README.md edited online with Bitbucket 2022-10-28 01:54:48 +00:00
Paulo Veiga
59d7ffd9c5 Fix creation table issue. 2022-10-28 01:45:18 +00:00
Paulo Gustavo Veiga
24e2ba93f3 Fix encoding on map title. 2022-10-24 19:02:41 -07:00
Paulo Gustavo Veiga
6cd0f635d5 Fix deleted object would be re-saved by cascade (remove deleted object from associations): [com.wisemapping.model.Collaboration#1651889] 2022-10-21 23:06:04 -07:00
Paulo Gustavo Veiga
4ee62035b8 Update spring framework version. 2022-10-21 18:58:36 -07:00
Paulo Gustavo Veiga
38639e18aa Bump up version. 2022-10-21 18:46:53 -07:00
Paulo Gustavo Veiga
e3a60102fb Update front-end version. 2022-10-21 18:43:08 -07:00
Paulo Gustavo Veiga
7c060ee192 Fix typo 2022-10-21 18:37:33 -07:00
Paulo Gustavo Veiga
2981fe79f7 Rename exception OnwerCollabCannotChangeException 2022-10-21 18:34:55 -07:00
Paulo Gustavo Veiga
c5009e8a07 Add automation for starred. 2022-10-21 17:44:59 -07:00
Paulo Gustavo Veiga
44bb67936b Add starred get endpoint 2022-10-21 17:26:19 -07:00
Paulo Gustavo Veiga
6b220ccb81 Fix bug scape ' on title name. 2022-10-21 16:05:41 -07:00
Paulo Gustavo Veiga
4d8c2aa6cb Inclease session timeout to 24 hs. 2022-10-19 17:36:46 -07:00
Paulo Gustavo Veiga
308092abbd Update MySQL schema 2022-10-18 21:14:49 -07:00
Paulo Gustavo Veiga
b97d5b1a00 Fix removal of maps shared in read-only. 2022-10-05 20:27:41 -07:00
Paulo Gustavo Veiga
ad84282ef8 Remove chache from user. 2022-10-03 21:23:38 -07:00
Paulo Veiga
5b4a6e4c78 Merged editor-with-mui into develop 2022-10-04 01:45:12 +00:00
Paulo Gustavo Veiga
103534475d Fix java.util.ConcurrentModificationException on User creation. 2022-10-03 18:18:30 -07:00
Paulo Gustavo Veiga
2146e2e457 Remove tags. 2022-10-03 16:14:23 -07:00
Paulo Gustavo Veiga
f0531551d7 Add unique to table. 2022-09-28 07:12:13 -07:00
Paulo Gustavo Veiga
e511d5e23d Improve registration code 2022-09-27 21:46:42 -07:00
Paulo Gustavo Veiga
aa6ac9bf7f Fix db error during account creation. 2022-09-27 20:14:32 -07:00
Paulo Gustavo Veiga
5f26874b47 Clean up dependencies on map delete 2022-09-27 18:47:56 -07:00
Paulo Gustavo Veiga
599bc9ec00 Revert NameMatchTransactionAttributeSource mapping. 2022-09-27 17:42:17 -07:00
Paulo Gustavo Veiga
708a42c560 Optimize to avoid single selects on OnToMany in mindmap. 2022-09-26 20:41:48 -07:00
Paulo Gustavo Veiga
86964febc1 Performance optimization to avoid loading Collaboration table per map. 2022-09-26 10:25:23 -07:00
Paulo Gustavo Veiga
0c88b8a474 Change to nexted for transaction propagation. 2022-09-26 08:42:55 -07:00
Paulo Gustavo Veiga
225a913a3a Change PROPAGATION_REQUIRED_NEW option. 2022-09-26 08:24:00 -07:00
Paulo Gustavo Veiga
047c8cce9d Revert condition change. 2022-09-24 09:52:45 -07:00
Paulo Gustavo Veiga
704fb1a880 Workaround to solve maps visibility problem on missing COLLABORATION entry. 2022-09-24 09:37:36 -07:00
Paulo Gustavo Veiga
b5e7389e41 Enable entities cache. 2022-09-24 08:39:11 -07:00
Paulo Gustavo Veiga
39bb8f458b Remove bootstrap for rendering. 2022-09-23 21:04:57 -07:00
Paulo Gustavo Veiga
242906d6d4 Fix layout specification 2022-09-12 21:59:10 -07:00
Paulo Gustavo Veiga
0301c5c63a Lazy loading on public view 2022-09-12 09:59:53 -07:00
Paulo Gustavo Veiga
befb252850 Lazy loading. 2022-09-12 09:46:02 -07:00
Paulo Gustavo Veiga
0c2c6c0b6e Add title to zoom in and zoom out buttons for view only 2022-09-11 16:35:08 -07:00
Paulo Gustavo Veiga
fecd5f3592 Add adds to public view
Add image width and height to icons
2022-09-11 16:23:25 -07:00
Paulo Gustavo Veiga
48eae09985 Update to async font load 2022-09-11 14:20:58 -07:00
Paulo Gustavo Veiga
b431c90758 Optimize font loading. 2022-09-11 13:57:55 -07:00
Paulo Gustavo Veiga
27f64e9feb New snapshot version 2022-09-11 13:28:44 -07:00
Paulo Gustavo Veiga
7af9822777 Complete new release. 2022-09-11 13:20:06 -07:00
Paulo Gustavo Veiga
5f687fa78b Update UI and spring boot dependencies. 2022-09-11 13:15:45 -07:00
Gonzalo Martinez
777a5a5212 Merged in mindplot-webcomponent (pull request #21)
Mindplot webcomponent

* webcomoponent poc in public view

* webcomponent in public view
2022-08-26 01:35:16 +00:00
Paulo Gustavo Veiga
485814f22a Add starred unit test 2022-08-06 16:54:27 -07:00
Paulo Gustavo Veiga
cb2436889b Fix bug cascade remove of label 2022-08-06 16:21:17 -07:00
Alejandro Raiczyk
f7369e33dc Merged in ray_fixes_ios (pull request #20)
center map zoom and position icons in the buttons

* center map zoom and position icons in the buttons
2022-08-05 02:15:05 +00:00
Gonzalo Martinez
edaa4b78f4 Merged in integration-test-incresed-coverage (pull request #19)
Integration test incresed coverage

* batchDelete test implementation

* updatePublishState test implementation

* RestMindmapHistory basic constructor for testing purpose

* fetchMapHistory test implementation

* updateRevertMindmap test implementation

* Coverage report in README

* correction

* updateRevertMindmap test improvement

* addCollab missed branches

* deleteCollab missed branches


Approved-by: Paulo Veiga
2022-07-29 23:19:14 +00:00
Paulo Veiga
8ffb48d095 Update email password for login in documentation. 2022-07-19 02:29:24 +00:00
Gustavo Fuhr
cf0d19de4e Revert change. 2022-07-15 01:00:34 +00:00
Gustavo Fuhr
845fb2f1df Merged in body-size-alternative (pull request #17)
alternative way to set body to fit browser window

* alternative way to set body to fit browser window
2022-07-14 03:12:56 +00:00
Gustavo Fuhr
8554fb7507 Merged in ray-develop (pull request #16)
Ray develop

* fix view and public mode, initial scale and body size

* Merged develop into ray-develop
* root container size now is defined with css

* Merge branch 'ray-develop' of bitbucket.org:wisemapping/wisemapping-open-source into ray-develop


Approved-by: Paulo Veiga
2022-07-09 01:35:06 +00:00
Gustavo Fuhr
a49b870f03 Merged in ray-develop (pull request #14)
PR ray-develop -> develop

* fix view and public mode, initial scale and body size


Approved-by: Paulo Veiga
2022-07-04 22:10:30 +00:00
Paulo Gustavo Veiga
0920dab922 Update readme documentation. 2022-06-29 18:24:42 -07:00
Paulo Gustavo Veiga
c5dca51df9 Simplify GA page title 2022-05-30 09:00:13 -07:00
Paulo Gustavo Veiga
038c4fa6fe Fix url typo 2022-05-29 22:07:38 -07:00
Paulo Gustavo Veiga
b44ace6992 Update GA4 for public 2022-05-29 21:47:44 -07:00
Paulo Gustavo Veiga
1290261966 Update Spring Framework version 2022-05-29 10:27:31 -07:00
Paulo Gustavo Veiga
d831c9d81f Improve control when owner try to be changed. 2022-04-15 00:21:38 -03:00
Paulo Gustavo Veiga
51cfa961e6 Improve handling change of ownner exception. 2022-04-14 16:37:18 -03:00
Paulo Gustavo Veiga
1cabb59b2f Bump up ui version. 2022-04-13 19:23:04 -03:00
Paulo Gustavo Veiga
0f1e0d29f2 Add support for base url configuration 2022-04-13 19:16:51 -03:00
Paulo Gustavo Veiga
deb4cf498a Minor fix 2022-04-12 08:27:53 -03:00
Paulo Gustavo Veiga
3732e858b5 Update robot.txt exclusions 2022-04-12 08:26:35 -03:00
Paulo Gustavo Veiga
3e9a5a0b12 Add exclusion list for domains. 2022-04-11 17:50:19 -03:00
Paulo Gustavo Veiga
7af7925610 Add control to limit the number of accounts to share. 2022-04-11 16:58:06 -03:00
Paulo Gustavo Veiga
c6ddadba45 Fix tooltip rendering. 2022-04-11 15:41:13 -03:00
Paulo Gustavo Veiga
50e0069532 Improve email template 2022-04-11 15:09:42 -03:00
Paulo Gustavo Veiga
b0517db79e Bump up version. 2022-04-11 14:51:43 -03:00
Paulo Gustavo Veiga
c76ae8da06 Release 5.0.11 2022-04-11 14:43:24 -03:00
Paulo Gustavo Veiga
b8b63509d0 Configure resources loading encoding. 2022-04-11 14:36:28 -03:00
Paulo Gustavo Veiga
735bb640b6 Minor fix 2022-04-11 10:05:30 -03:00
Paulo Gustavo Veiga
f1cfef8cf0 Improve message translation on email 2022-04-11 10:03:27 -03:00
Paulo Gustavo Veiga
e435cd4666 Fix file encoding issue on emails. 2022-04-11 09:51:15 -03:00
Paulo Gustavo Veiga
08374056cc Disable cache on entitles. 2022-04-04 23:04:57 -03:00
Paulo Gustavo Veiga
86a0a876ca Fix error trying to delete account with labels created. 2022-04-03 22:02:20 -03:00
Paulo Gustavo Veiga
a618849afc Remove REST API application/xml type support 2022-04-02 12:59:54 -03:00
Paulo Gustavo Veiga
ad20d06d19 Update spring framework version. 2022-04-02 12:22:25 -03:00
Paulo Gustavo Veiga
accf252e78 Fix email encodding problem. 2022-03-30 07:50:42 -03:00
Paulo Gustavo Veiga
641bcbbe17 Fix reset passwod issue on message. 2022-03-30 07:45:15 -03:00
Paulo Gustavo Veiga
8248e162fe Enable base url discovery. 2022-03-29 22:41:21 -03:00
Paulo Gustavo Veiga
6f19323292 Add debug information. 2022-03-28 08:15:46 -03:00
Paulo Gustavo Veiga
8a5bd2de94 Remove junit unsed dependency 2022-03-27 22:55:44 -03:00
Paulo Gustavo Veiga
6508b9eb67 Revert jslt scope change 2022-03-27 22:52:08 -03:00
Paulo Gustavo Veiga
1ac332a18e Revert "Exclude version in collition"
This reverts commit e9ff9b36fc.
2022-03-27 22:46:34 -03:00
Paulo Gustavo Veiga
e9ff9b36fc Exclude version in collition 2022-03-27 22:44:53 -03:00
Paulo Gustavo Veiga
5fa6a82b3a Update java dependencies. 2022-03-27 20:05:21 -03:00
Paulo Gustavo Veiga
de5febaf15 Bump up version 2022-03-27 15:04:19 -03:00
271 changed files with 6098 additions and 7038 deletions

35
.github/workflows/maven.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: WiseMapping API
on:
push:
branches: [ "develop" ]
pull_request:
branches: [ "develop" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'zulu'
cache: maven
- name: Build with Maven
run: mvn -B clean package --file wise-api/pom.xml
- name: Build the Docker image
run: docker build -t wisemapping/wisemapping-api:latest wise-api
# Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
#- name: Update dependency graph
# uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6

15
LICENSE.md Normal file
View File

@@ -0,0 +1,15 @@
# WiseMapping Public License Version 1.0 (WPL)
WiseMapping open source edition is licensed under the WiseMapping Public License Version 1.0. It is basically Apache License Version 2.0 plus the "powered by wisemapping" text requirement on every single page (the "License") unless we authorize you to remove it.
The WiseMapping Public License Version 1.0 ("WPL") consists of the [APACHE LICENSE, VERSION 2.0](http://www.apache.org/licenses/LICENSE-2.0), modified to be specific to WiseMapping, with the Additional Terms in Exhibit B.
Unless Required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
## EXHIBIT B - WiseMapping Public License.
Additional Terms applicable to the WiseMapping Public License.
I. Effect.
These additional terms described in this wiseMapping Public License - Additional Terms shall apply to the Covered Code under this License.
II. WiseMapping and "powered by WiseMapping" text.
This License does not grant any rights to use the trademarks "WiseMapping" even if such marks are included in the Original Code or Modifications.
However, in addition to the other notice obligations, unless wisemapping founders authorize you by email not to do it, (1) all copies of the Original Code in Executable and Source Code form must, as a form of attribution of the original author, include on each user interface screen (i) the "powered by WiseMapping" text; and (2) all derivative works and copies of derivative works of the Covered Code in Executable and Source Code form must include on each user interface screen (i) the "powered by WiseMapping" text. In addition, the "powered by WiseMapping" text, as appropriate, must be visible to all users, must appear in each user interface screen, and must be in the same position. When users click on the "powered by WiseMapping" text it must direct them to http://www.wisemapping.com. This obligation shall also apply to any copies or derivative works which are distributed under the alternative terms of Section 3.6 and this obligation must be included in any such license

View File

@@ -1,75 +1,89 @@
# Overview
# WiseMapping Open Source
Wise Mapping is the web mind mapping open source tool that leverages the power of Mind Maps mixing open standards technologies such as SVG and React.
WiseMapping is based on the same code product supporting [http://www.wisemapping.com].
WiseMapping is an open-source web-based mind mapping tool that harnesses the potential of Mind Maps by blending together open standards technologies like SVG and React. It is built upon the foundation of the code supporting http://www.wisemapping.com, ensuring reliability and continuity in its development.
## Compiling and Running
# Build and Start Application
### Prerequisites
The following section describes the steps to check out, compile, and start WiseMapping locally. If you are interested in deploying it, I recommend using the already published images https://hub.docker.com/r/wisemapping/wisemapping.
The following products must be installed:
## Prerequisites
* OpenJDK 11 or higher
* Maven 3.x or higher ([http://maven.apache.org/])
* npm 6 or higher ([https://www.npmjs.com/package/npm?activeTab=versions])
* JDK 21 or higher
* Maven v3.x or higher ([http://maven.apache.org/])
* Yarn v1 or higher
* Node v18 or higher
### Compiling
## Option 1: Quick Start with Docker Compose
WiseMapping uses Maven as packaging and project management. It's composed of 5 maven sub-modules:
The following command line will start WiseMapping locally using HSQLDB in memory for development purposes:
* wise-ui: React font-end fetcher
* wise-webapp: J2EE web application
```
$ mvn -f wise-api/pom.xml package
$ docker compose up --build
```
The full compilation of the project can be performed executing within <project-dir>:
Application will start at http://localhost/c/login. You can login using *test@wisemapping.org* and password *test*
`mvn clean install`
## Option 2: Start Frontend and Backend API
Once this command is executed, the file <project-dir>/wise-webapp/target/wisemapping*.war will be generated.
### Compile and Start API
### Local Development
The previously generated war can be deployed locally executing within the directory <project-dir>/wise-webapp the following command:
```
$ mvn -f wise-api/pom.xml package
$ cd wise-api
$ mvn spring-boot:run
```
`cd wise-webapp;mvn jetty:run-war`
### Compile and Start Frontend
This will start the application on the URL: [http://localhost:8080/] using file based database.
You need to checkout https://github.com/wisemapping/wisemapping-frontend first. Then, follow the next steps:
User: test@wisemapping.org
Password: test
```
$ export NODE_OPTIONS=--openssl-legacy-provider
$ export APP_CONFIG_TYPE="file:dev"
### Local Development + UI Integration
$ cd wisemapping-frontend
$ yarn install
$ yarn build
In order to reduce the life-cycle to develop UI backend testing, you can do the following hack:
$ cd packages/webapp; yarn start
```
Application will start at http://localhost:3000/c/login. You can login using *test@wisemapping.org* and password *test*
* Clone [wisemapping-open-source](https://bitbucket.org/wisemapping/wisemapping-open-source/) and [wisemapping-frontend](https://bitbucket.org/wisemapping/wisemapping-frontend/) at the same top level directory
* Compile `wisemapping-frontend`. Details for compilation can be found in the `wisemapping-frontend` readme.
* Compile `wisemapping-open-source`
# Supportability Matrix
A quick and dirty solution to share changes in the UI is to manually compile the dist. This will make the loader file available without the need to publish:
## Databases
`yarn --cwd wisemapping-frontend build;cp -r wisemapping-frontend/packages/mindplot/dist/* wisemapping-open-source/wise-ui/target/wisemapping-mindplot/package/dist;cp -r wisemapping-frontend/packages/mindplot/dist/* wisemapping-open-source/wise-ui/target/wisemapping-mindplot/package/dist`
* MySQL v8 or higher
* PostgreSQL v15 or higher
* Hsqldb v2.7 or higher
# Configuration
### Compiling and running with docker-compose
WiseMapping backend is based on SpringBoot v3 and it's highly customizable. Additional documentation can be found [here](https://docs.spring.io/spring-boot/3.3/reference/features/external-config.html)
Check out the [docker section](./docker/README.
The perfered option is to extended by overwriting [application.yaml](https://github.com/wisemapping/wisemapping-open-source/blob/develop/wise-api/src/main/resources/application.yml)
## Members
```
$ java -jar target/wisemapping-api.jar --spring.config.additional-location=../../wise-conf/app.yml
```
### Founders
For example, this [example](https://github.com/wisemapping/wisemapping-open-source/blob/develop/config/database/postgresql/app-postgresql.yaml) configure PostgreSQL as database.
# Members
## Founders
* Paulo Veiga <pveiga@wisemapping.com>
* Pablo Luna <pablo@wisemapping.com>
### Individual Contributors
## Past Individual Contributors
* Ignacio Manzano
* Ezequiel Bergamaschi <ezequielbergamaschi@gmail.com>
### Past Individual Contributors
* Ignacio Manzano
## License
The source code is Licensed under the WiseMapping Open License, Version 1.0 (the “License”);
You may obtain a copy of the License at: [https://wisemapping.atlassian.net/wiki/display/WS/License]
You may obtain a copy of the License at: [https://github.com/wisemapping/wisemapping-open-source/blob/develop/LICENSE.md](https://github.com/wisemapping/wisemapping-open-source/blob/develop/LICENSE.md)

View File

@@ -1,39 +0,0 @@
# Template maven-build
# This template allows you to test and build your Java project with Maven.
# The workflow allows running tests, code checkstyle and security scans on the default branch.
# Prerequisites: pom.xml and appropriate project structure should exist in the repository.
image: maven:3.6.3
pipelines:
branches:
'{master,develop}':
- step:
name: Build and Test
caches:
- node
- maven
- docker
script:
# Compile sources ...
- curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.36.0/install.sh | bash
- . $HOME/.nvm/nvm.sh && nvm install node
- mvn -B verify --file pom.xml
# Publish to docker repo ...
- docker login --username $DOCKER_USERNAME --password $DOCKER_PASSWORD
- docker build -t wisemapping/wisemapping:latest -f distribution/Dockerfile wise-webapp/target/
- docker push wisemapping/wisemapping:latest
after-script:
# Collect checkstyle results, if any, and convert to Bitbucket Code Insights.
- pipe: atlassian/checkstyle-report:0.3.0
services:
- docker
- step:
name: Security Scan
script:
# Run a security scan for sensitive data.
# See more security tools at https://bitbucket.org/product/features/pipelines/integrations?&category=security
- pipe: atlassian/git-secrets-scan:0.5.1

45
config/README.md Normal file
View File

@@ -0,0 +1,45 @@
# Database Configuration
## Overview
WiseMapping supports a wide variety of databases. However, we run intensively tests over HSQL and MySQL database.
* HyperSQL: Automatically configured when you compile WiseMapping and It's used primarily for testing. Additionally, the binary distribution already has an instance configured to provide a single click installation.
* MySQL: This version is the most tested database we support. MySQL is the database use in http://www.wisemapping.com and it's the suggested version for production environments.
* PostgreSQL: Scripts are distributed for the creation and configuration of the it. You will find them within "config/postgres" directory in the binary distribution. Additionally, JDBC driver need to be added to the container.
* Others: In spite of the fact that we don't provide yet initialization scripts for others databases, WiseMapping can be deployed in any relational database. Please, contact us if you have any particular question on this area.
* In the following section, you are going to find a detailed explanation how to configure you WiseMapping using MySQL 5.5.
## MySQL Installation
### Prerequisites
* Download and install MySQL. You can download it for free from: http://dev.mysql.com/downloads/
Running SQL Scripts
Inside the WiseMapping binary distribution, you will find a directory "config/mysql". It contains all the SQL script required to configure a new WiseMapping database instance.
You will find 4 scripts:
* create-database.sql: Create all wisemapping database and wisemapping user.
* create-schemas.sql: Create all database tables and index.
* apopulate-schemas.sql: Creates a mind map example and an a test user "test@wisemapping.org" with password "test".
* drop-schemas.sql: Drop all wisemapping tables in case you want to have a fresh installation.
There are a lot of good tools you can use to run this scripts (eg: MySQLWorkbench). However, the simples way is to use the command line tool that is distributed as part of the MySQL installation.
If you are one brave hearts that is not afraid of the command line tools, open a terminar and execute the following lines:
~~~~
cd <WISEMAPPING-DIR>/config/database/mysql
# Default MySQL installation creates a "root" user with empty password. You can connect to the database with this user if you are # logged in same machine where the database is installed and must be executed logged as "root"
#
# If you have changed the default database "root" password , you need to specify an additional -p parameter and provide the
# new password.
mysql -uroot < create-database.sql
# Create tables and default tests user
mysql -uwisemapping -Dwisemapping -ppassword < create-schemas.sql
mysql -uwisemapping -Dwisemapping -ppassword < apopulate-schemas.sql
~~~~
Great, you have configured you database !. Let's configure WiseMapping now.

View File

@@ -1,10 +0,0 @@
INSERT INTO COLLABORATOR (id, email, creation_date) VALUES (1, 'test@wisemapping.org', CURDATE());
INSERT INTO USER (colaborator_id, firstname, lastname, password, activation_code, activation_date, allow_send_email,authentication_type)
VALUES (1, 'Test', 'User', 'ENC:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3', 1237, CURDATE(), 1,'D');
INSERT INTO COLLABORATOR (id, email, creation_date) VALUES (2, 'admin@wisemapping.org', CURDATE());
INSERT INTO USER (colaborator_id, firstname, lastname, password, activation_code, activation_date, allow_send_email,authentication_type)
VALUES (2, 'Admin', 'User', 'ENC:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3', 1237, CURDATE(), 1,'D');
COMMIT;
SHUTDOWN;

View File

@@ -1,96 +0,0 @@
CREATE TABLE COLLABORATOR (
id INTEGER NOT NULL IDENTITY,
email VARCHAR(255) NOT NULL,
creation_date DATE
);
CREATE TABLE USER (
colaborator_id INTEGER NOT NULL IDENTITY,
authentication_type CHAR(1) NOT NULL,
authenticator_uri VARCHAR(255) NULL,
firstname VARCHAR(255) NOT NULL,
lastname VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
activation_code BIGINT NOT NULL,
activation_date DATE,
allow_send_email CHAR(1) NOT NULL,
locale VARCHAR(5),
FOREIGN KEY (colaborator_id) REFERENCES COLLABORATOR (id)
);
CREATE TABLE MINDMAP (
id INTEGER NOT NULL IDENTITY,
title VARCHAR(255) NOT NULL,
description VARCHAR(255) NOT NULL,
xml LONGVARBINARY NOT NULL,
public BOOLEAN NOT NULL,
creation_date DATETIME,
edition_date DATETIME,
creator_id INTEGER NOT NULL,
tags VARCHAR(1014),
last_editor_id INTEGER NOT NULL
--FOREIGN KEY(creator_id) REFERENCES USER(colaborator_id)
);
CREATE TABLE LABEL (
id INTEGER NOT NULL PRIMARY KEY IDENTITY,
title VARCHAR(30),
creator_id INTEGER NOT NULL,
parent_label_id INTEGER,
color VARCHAR(7) NOT NULL,
iconName VARCHAR(50) NOT NULL
--FOREIGN KEY (creator_id) REFERENCES USER (colaborator_id)
);
CREATE TABLE R_LABEL_MINDMAP (
mindmap_id INTEGER NOT NULL,
label_id INTEGER NOT NULL,
PRIMARY KEY (mindmap_id, label_id),
FOREIGN KEY (mindmap_id) REFERENCES MINDMAP (id),
FOREIGN KEY (label_id) REFERENCES LABEL (id) ON DELETE CASCADE ON UPDATE NO ACTION
);
CREATE TABLE MINDMAP_HISTORY (
id INTEGER NOT NULL IDENTITY,
xml LONGVARBINARY NOT NULL,
mindmap_id INTEGER NOT NULL,
creation_date DATETIME,
editor_id INTEGER NOT NULL,
FOREIGN KEY (mindmap_id) REFERENCES MINDMAP (id)
);
CREATE TABLE COLLABORATION_PROPERTIES (
id INTEGER NOT NULL IDENTITY,
starred BOOLEAN NOT NULL,
mindmap_properties VARCHAR(512)
);
CREATE TABLE COLLABORATION (
id INTEGER NOT NULL IDENTITY,
colaborator_id INTEGER NOT NULL,
properties_id INTEGER NOT NULL,
mindmap_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
FOREIGN KEY (colaborator_id) REFERENCES COLLABORATOR (id),
FOREIGN KEY (mindmap_id) REFERENCES MINDMAP (id),
FOREIGN KEY (properties_id) REFERENCES COLLABORATION_PROPERTIES (id)
);
CREATE TABLE TAG (
id INTEGER NOT NULL IDENTITY,
name VARCHAR(255) NOT NULL,
user_id INTEGER NOT NULL,
--FOREIGN KEY(user_id) REFERENCES USER(colaborator_id)
);
CREATE TABLE ACCESS_AUDITORY (
id INTEGER NOT NULL IDENTITY,
user_id INTEGER NOT NULL,
login_date DATE,
FOREIGN KEY (user_id) REFERENCES USER (colaborator_id)
ON DELETE CASCADE
ON UPDATE NO ACTION
);
COMMIT;

View File

@@ -1,11 +0,0 @@
DROP TABLE IF EXISTS ACCESS_AUDITORY;
DROP TABLE IF EXISTS TAG;
DROP TABLE IF EXISTS COLLABORATION;
DROP TABLE IF EXISTS COLLABORATION_PROPERTIES;
DROP TABLE IF EXISTS MINDMAP_HISTORY;
DROP TABLE IF EXISTS R_LABEL_MINDMAP;
DROP TABLE IF EXISTS LABEL;
DROP TABLE IF EXISTS MINDMAP;
DROP TABLE IF EXISTS USER;
DROP TABLE IF EXISTS COLLABORATOR;
COMMIT;

View File

@@ -0,0 +1,10 @@
RENAME TABLE USER TO ACCOUNT;
RENAME TABLE LABEL TO MINDMAP_LABEL;
ALTER TABLE COLLABORATION
RENAME COLUMN colaborator_id to collaborator_id;
ALTER TABLE ACCOUNT
RENAME COLUMN colaborator_id to collaborator_id;
ALTER TABLE MINDMAP_LABEL DROP COLUMN iconName;

View File

@@ -1,13 +0,0 @@
#
# Command: mysql -u root -p < apopulate_schemas.sql
#
INSERT INTO COLLABORATOR (id, email, creation_date) VALUES (1, 'test@wisemapping.org', CURRENT_DATE());
INSERT INTO USER (colaborator_id, firstname, lastname, password, activation_code, activation_date, allow_send_email,authentication_type)
VALUES (1, 'Test', 'User', 'ENC:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3', 1237, CURRENT_DATE(), 1,'D');
INSERT INTO COLLABORATOR (id, email, creation_date) VALUES (2, 'admin@wisemapping.org', CURRENT_DATE());
INSERT INTO USER (colaborator_id, firstname, lastname, password, activation_code, activation_date, allow_send_email,authentication_type)
VALUES (2, 'Admin', 'User', 'ENC:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3', 1237, CURRENT_DATE(), 1,'D');
COMMIT;

View File

@@ -0,0 +1,14 @@
spring:
datasource:
url: jdbc:mysql://localhost:3306/wisemapping?useUnicode=yes&characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
password: password
username: wisemapping
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.MySQLDialect
sql:
init:
platform: mysql

View File

@@ -1,10 +1,12 @@
#
# Command: mysql -u root -p < create_database.sql
#
DROP DATABASE IF EXISTS wisemapping;
CREATE DATABASE IF NOT EXISTS wisemapping
CHARACTER SET = 'utf8'
COLLATE = 'utf8_unicode_ci';
GRANT ALL ON wisemapping.* TO 'wisemapping'@'localhost';
SET PASSWORD FOR 'wisemapping'@'localhost' = PASSWORD('password');
#
# Command: mysql -u root -p < create-database.sql
#
DROP DATABASE IF EXISTS wisemapping;
CREATE DATABASE IF NOT EXISTS wisemapping
CHARACTER SET = 'utf8'
COLLATE = 'utf8_unicode_ci';
CREATE USER 'wisemapping'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON wisemapping.* TO 'wisemapping'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

View File

@@ -1,11 +0,0 @@
DROP TABLE IF EXISTS TAG;
DROP TABLE IF EXISTS ACCESS_AUDITORY;
DROP TABLE IF EXISTS COLLABORATION;
DROP TABLE IF EXISTS COLLABORATION_PROPERTIES;
DROP TABLE IF EXISTS MINDMAP_HISTORY;
DROP TABLE IF EXISTS LABEL;
DROP TABLE IF EXISTS MINDMAP;
DROP TABLE IF EXISTS R_LABEL_MINDMAP
DROP TABLE IF EXISTS USER;
DROP TABLE IF EXISTS COLLABORATOR;
COMMIT;

View File

@@ -1,57 +0,0 @@
CREATE TABLE COLLABORATION_PROPERTIES (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
starred BOOL NOT NULL DEFAULT 0,
mindmap_properties VARCHAR(512)
CHARACTER SET utf8
)
CHARACTER SET utf8;
DROP TABLE `MINDMAP_NATIVE`;
ALTER TABLE `MINDMAP_COLABORATOR` RENAME TO `COLLABORATION`;
ALTER TABLE `COLABORATOR` RENAME TO `COLLABORATOR`;
ALTER TABLE `MINDMAP` DROP COLUMN `editor_properties`, DROP COLUMN `mindMapNative_id`;
ALTER TABLE `MINDMAP` CHANGE COLUMN `owner_id` `creator_id` INT(11) NOT NULL
, DROP INDEX `owner_id`
, ADD INDEX `owner_id` (`creator_id` ASC);
ALTER TABLE `COLLABORATION` ADD COLUMN `properties_id` INT(11) NULL DEFAULT NULL
AFTER `role_id`;
DROP TABLE USER_LOGIN;
CREATE TABLE ACCESS_AUDITORY (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
user_id INTEGER NOT NULL,
login_date DATE
)
CHARACTER SET utf8;
#ALTER TABLE ACCESS_AUDITORY
# ADD CONSTRAINT `user_id`
# FOREIGN KEY ()
# REFERENCES `USER` ()
# ON DELETE CASCADE
# ON UPDATE NO ACTION
#, ADD INDEX `user_id` () ;
ALTER TABLE `MINDMAP_HISTORY` DROP COLUMN `creator_user`, ADD COLUMN `editor_id` INT(11) NULL DEFAULT NULL AFTER `creation_date`;
ALTER TABLE `USER` ADD COLUMN `locale` VARCHAR(5) NULL
AFTER `allowSendEmail`;
ALTER TABLE `MINDMAP` DROP COLUMN `last_editor`, ADD COLUMN `last_editor_id` INT(11) NULL DEFAULT 2
AFTER `tags`;
ALTER TABLE `USER` DROP COLUMN `username`, CHANGE COLUMN `activationCode` `activation_code` BIGINT(20) NOT NULL, CHANGE COLUMN `allowSendEmail` `allow_send_email` CHAR(1) NOT NULL DEFAULT '0';
INSERT INTO `MINDMAP` (`last_editor_id`) VALUES (1);
INSERT INTO `COLLABORATOR` (`id`, `email`, `creation_date`) VALUES (8081, 'migfake@wis.com', '2007-10-09');
DELETE FROM `USER`
WHERE activation_date IS null;
DROP TABLE FEEDBACK;
ALTER TABLE `MINDMAP` CHANGE COLUMN `XML` `XML` MEDIUMBLOB NULL DEFAULT NULL;
ALTER TABLE `MINDMAP_HISTORY` CHANGE COLUMN `XML` `XML` MEDIUMBLOB NULL DEFAULT NULL;

View File

@@ -1,5 +0,0 @@
ALTER TABLE `USER` ADD COLUMN `authentication_type` CHAR(1) CHARACTER SET utf8 NOT NULL DEFAULT 'D'
AFTER `colaborator_id`;
ALTER TABLE `USER` ADD COLUMN `authenticator_uri` VARCHAR(255) CHARACTER SET utf8
AFTER `authentication_type`;

View File

@@ -1,37 +0,0 @@
ALTER TABLE `USER` DROP COLUMN `id`;
ALTER TABLE `ACCESS_AUDITORY`
ADD CONSTRAINT
FOREIGN KEY (user_id) REFERENCES USER (colaborator_id)
ON DELETE CASCADE
ON UPDATE NO ACTION;
CREATE TABLE LABEL (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(30)
CHARACTER SET utf8 NOT NULL,
creator_id INTEGER NOT NULL,
parent_label_id INTEGER,
color VARCHAR(7) NOT NULL,
FOREIGN KEY (creator_id) REFERENCES USER (colaborator_id),
FOREIGN KEY (parent_label_id) REFERENCES LABEL (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
CREATE TABLE R_LABEL_MINDMAP (
mindmap_id INTEGER NOT NULL,
label_id INTEGER NOT NULL,
PRIMARY KEY (mindmap_id, label_id),
FOREIGN KEY (mindmap_id) REFERENCES MINDMAP (id),
FOREIGN KEY (label_id) REFERENCES LABEL (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
ALTER TABLE `LABEL`
ADD COLUMN iconName VARCHAR(50) NOT NULL;
UPDATE LABEL SET iconName = 'glyphicon glyphicon-tag';

View File

@@ -1,3 +0,0 @@
CREATE DATABASE wisemapping;
CREATE USER wisemapping WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE wisemapping TO wisemapping;

View File

@@ -1,11 +0,0 @@
DROP TABLE TAG;
DROP TABLE ACCESS_AUDITORY;
DROP TABLE COLLABORATION;
DROP TABLE COLLABORATION_PROPERTIES;
DROP TABLE MINDMAP_HISTORY;
DROP TABLE R_LABEL_MINDMAP;
DROP TABLE LABEL;
DROP TABLE MINDMAP;
DROP TABLE "user";
DROP TABLE COLLABORATOR;
COMMIT;

View File

@@ -0,0 +1,14 @@
spring:
datasource:
url: jdbc:postgresql://localhost/wisemapping
driver-class-name: org.postgresql.Driver
password: password
username: wisemapping
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
sql:
init:
platform: postgresql

View File

@@ -0,0 +1,7 @@
CREATE DATABASE wisemapping;
CREATE USER wisemapping WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE wisemapping TO wisemapping;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO wisemapping;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO wisemapping;

View File

@@ -2,7 +2,8 @@
# Based on ubuntu:latest, installs WiseMapping (http://ww.wisemapping.org)
# Based info setup ...
FROM tomcat:9.0-jdk17-openjdk
#FROM --platform=$BUILDPLATFORM tomcat:9.0.71-jdk17
FROM tomcat:10.1.11-jdk17
LABEL maintainer="Paulo Gustavo Veiga <pveiga@wisemapping.com>"
# Build variables ...
@@ -10,7 +11,7 @@ ARG WEBAPP_TARGET_DIR="/usr/local/tomcat/webapps/ROOT"
ARG DB_BASE_DIR="/var/lib/wisemapping"
# Default ENV configurations ...
ENV JAVA_OPTS="-XX:+PrintFlagsFinal -XX:InitialRAMPercentage=30 -XX:MaxRAMPercentage=80"
ENV JAVA_OPTS="-XX:+PrintFlagsFinal -XX:InitialRAMPercentage=30 -XX:MaxRAMPercentage=80 -Dfile.encoding=UTF-8"
ENV database.base.url=${DB_BASE_DIR}
# Copy wisemapping distribution ...
@@ -20,7 +21,7 @@ RUN cd ${WEBAPP_TARGET_DIR} && jar -xvf /tmp/wisemapping.war
RUN rm /tmp/wisemapping.war
# Change logger to
RUN cp ${WEBAPP_TARGET_DIR}/WEB-INF/classes/log4j-stdout.properties ${WEBAPP_TARGET_DIR}/WEB-INF/classes/log4j.properties
RUN cp ${WEBAPP_TARGET_DIR}/WEB-INF/log4j2-stdout.xml ${WEBAPP_TARGET_DIR}/WEB-INF/classes/log4j2.xml
# Add support for proxy
RUN sed -i 's|\

View File

@@ -9,15 +9,27 @@ There are multiple ways to run WiseMapping depending on your database configurat
## Option 1: Running HSQL within the image storage
> $ docker run -it --rm -p 8080:8080 veigap/wisemapping:latest>
> $ docker run -it --rm -p 8080:8080 wisemapping/wisemapping:latest
Then, open your browser at `http://localhost:8888`. A default user is available for testing `test@wisemapping.com` and password `test`.
Then, open your browser at `http://localhost:8888`. A default user is available for testing `test@wisemapping.org` and password `test`.
***This option, all changes will be lost once the image is stopped. Use it for testing only***
## Option 2: Running HSQL with mounted directory
> $ docker run -it --rm -p 8080:8080 veigap/wisemapping:latest
Only one time, copy the empty default out of the container:
> $ mkdir your- db-dir-store-path
>
> $ docker run --name wiseapp -d --mount type=bind,source=your-db-dir-store-path,target=/var/lib/wise-db wisemapping/wisemapping:latest
>
> $ docker cp wiseapp:/var/lib/wisemapping/db your-db-dir-store-path
>
> $ docker stop wiseapp;docker rm wiseapp
Then, execute the container mounting tbe directory:
> $ docker run --mount type=bind,source=your-db-dir-store-path/db,target=/var/lib/wisemapping/db -it --rm -p 8080:8080 wisemapping/wisemapping:latest
## Option 3: External MySQL/PostgreSQL
@@ -30,13 +42,13 @@ Depending on the database your want to configure, you can create initialization
The next step is configure the WiseMapping for the database and credentials.
Download `app.properties` configuration file and configure the required sections:
> $ curl https://bitbucket.org/wisemapping/wisemapping-open-source/raw/644b7078d790220c7844b732a83d45495f11d64e/wise-webapp/src/main/webapp/WEB-INF/app.properties
> $ curl https://bitbucket.org/wisemapping/wisemapping-open-source/src/master/wise-webapp/src/main/webapp/WEB-INF/app.properties
### Starting the application
Run the application mounting your previously configured `app.properties`
> $ docker run --mount type=bind,source=your-file-path/app.properties,target=/usr/local/tomcat/webapps/ROOT/WEB-INF/app.properties -it --rm -p 8080:8080 veigap/wisemapping:latest
> $ docker run --mount type=bind,source=your-file-path/app.properties,target=/usr/local/tomcat/webapps/ROOT/WEB-INF/app.properties -it --rm -p 8080:8080 wisemapping/wisemapping:latest
# Advanced configuration

View File

@@ -4,4 +4,7 @@ set -o
set -u
mvn -f ../pom.xml clean package
docker build -t wisemapping/wisemapping:latest -f ./Dockerfile ../wise-webapp/target/
docker build --platform linux/amd64 -t wisemapping/wisemapping:latest -f ./Dockerfile ../wise-webapp/target/
#docker buildx create --use --platform=linux/arm64,linux/amd64 --name multi-platform-builder
#docker buildx inspect --bootstrap
#docker buildx build --platform=linux/amd64,linux/arm64 --push -t wisemapping/wisemapping:latest -f ./Dockerfile ../wise-webapp/target/

View File

@@ -1,10 +0,0 @@
#
# Command: mysql -u root -p < create_database.sql
#
DROP DATABASE IF EXISTS wisemapping;
CREATE DATABASE IF NOT EXISTS wisemapping
CHARACTER SET = 'utf8'
COLLATE = 'utf8_unicode_ci';
GRANT ALL ON wisemapping.* TO 'wisemapping'@'localhost';
SET PASSWORD FOR 'wisemapping'@'localhost' = PASSWORD('password');

View File

@@ -1,137 +0,0 @@
#
# Command: mysql -u root -p < create_schemas.sql
#
USE wisemapping;
CREATE TABLE COLLABORATOR (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255)
CHARACTER SET utf8 NOT NULL UNIQUE,
creation_date DATE
)
CHARACTER SET utf8;
CREATE TABLE USER (
colaborator_id INTEGER NOT NULL PRIMARY KEY,
authentication_type CHAR(1)
CHARACTER SET utf8 NOT NULL,
authenticator_uri VARCHAR(255)
CHARACTER SET utf8,
firstname VARCHAR(255) CHARACTER SET utf8 NOT NULL,
lastname VARCHAR(255) CHARACTER SET utf8 NOT NULL,
password VARCHAR(255) CHARACTER SET utf8 NOT NULL,
activation_code BIGINT(20) NOT NULL,
activation_date DATE,
allow_send_email CHAR(1) CHARACTER SET utf8 NOT NULL DEFAULT 0,
locale VARCHAR(5),
FOREIGN KEY (colaborator_id) REFERENCES COLLABORATOR (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
CREATE TABLE MINDMAP (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255)
CHARACTER SET utf8 NOT NULL,
description VARCHAR(255)
CHARACTER SET utf8 NOT NULL,
xml MEDIUMBLOB NOT NULL,
public BOOL NOT NULL DEFAULT 0,
creation_date DATETIME,
edition_date DATETIME,
creator_id INTEGER NOT NULL,
tags VARCHAR(1014)
CHARACTER SET utf8,
last_editor_id INTEGER NOT NULL,
FOREIGN KEY (creator_id) REFERENCES USER (colaborator_id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
CREATE TABLE LABEL (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(30)
CHARACTER SET utf8 NOT NULL,
creator_id INTEGER NOT NULL,
parent_label_id INTEGER,
color VARCHAR(7) NOT NULL,
iconName VARCHAR(50) NOT NULL,
FOREIGN KEY (creator_id) REFERENCES USER (colaborator_id),
FOREIGN KEY (parent_label_id) REFERENCES LABEL (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
CREATE TABLE R_LABEL_MINDMAP (
mindmap_id INTEGER NOT NULL,
label_id INTEGER NOT NULL,
PRIMARY KEY (mindmap_id, label_id),
FOREIGN KEY (mindmap_id) REFERENCES MINDMAP (id),
FOREIGN KEY (label_id) REFERENCES LABEL (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
CREATE TABLE MINDMAP_HISTORY
(id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
xml MEDIUMBLOB NOT NULL,
mindmap_id INTEGER NOT NULL,
creation_date DATETIME,
editor_id INTEGER NOT NULL,
FOREIGN KEY (mindmap_id) REFERENCES MINDMAP (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
CREATE TABLE COLLABORATION_PROPERTIES (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
starred BOOL NOT NULL DEFAULT 0,
mindmap_properties VARCHAR(512)
CHARACTER SET utf8
)
CHARACTER SET utf8;
CREATE TABLE COLLABORATION (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
colaborator_id INTEGER NOT NULL,
properties_id INTEGER NOT NULL,
mindmap_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
FOREIGN KEY (colaborator_id) REFERENCES COLLABORATOR (id),
FOREIGN KEY (mindmap_id) REFERENCES MINDMAP (id)
ON DELETE CASCADE
ON UPDATE NO ACTION,
FOREIGN KEY (properties_id) REFERENCES COLLABORATION_PROPERTIES (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
CREATE TABLE TAG (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255)
CHARACTER SET utf8 NOT NULL,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES USER (colaborator_id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
CREATE TABLE ACCESS_AUDITORY (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
login_date DATE,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES USER (colaborator_id)
ON DELETE CASCADE
ON UPDATE NO ACTION
)
CHARACTER SET utf8;
COMMIT;

View File

@@ -1,13 +0,0 @@
#
# Command: mysql -u root -p < apopulate_schemas.sql
#
INSERT INTO COLLABORATOR (id, email, creation_date) VALUES (1, 'test@wisemapping.org', CURRENT_DATE());
INSERT INTO USER (colaborator_id, firstname, lastname, password, activation_code, activation_date, allow_send_email,authentication_type)
VALUES (1, 'Test', 'User', 'ENC:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3', 1237, CURRENT_DATE(), 1,'D');
INSERT INTO COLLABORATOR (id, email, creation_date) VALUES (2, 'admin@wisemapping.org', CURRENT_DATE());
INSERT INTO USER (colaborator_id, firstname, lastname, password, activation_code, activation_date, allow_send_email,authentication_type)
VALUES (2, 'Admin', 'User', 'ENC:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3', 1237, CURRENT_DATE(), 1,'D');
COMMIT;

View File

@@ -0,0 +1,4 @@
ALTER TABLE USER
ADD COLUMN `google_sync` TINYINT(1) NULL,
ADD COLUMN `sync_code` VARCHAR(255) NULL,
ADD COLUMN `google_token` VARCHAR(255) NULL;

View File

@@ -0,0 +1,4 @@
ALTER TABLE "user"
ADD COLUMN `google_sync` BOOLEAN NULL,
ADD COLUMN `sync_code` VARCHAR(255) NULL,
ADD COLUMN `google_token` VARCHAR(255) NULL;

22
docker-compose.yml Normal file
View File

@@ -0,0 +1,22 @@
version: '3'
services:
wise-api:
container_name: wise-api
hostname: wise-api
image: wise-api:latest
build:
context: ./wise-api
dockerfile: Dockerfile
ports:
- "8080:8080"
wise-ui:
container_name: wise-ui
image: wise-ui:latest
build:
context: ./wise-ui
dockerfile: Dockerfile
depends_on:
- wise-api
ports:
- "80:80"

View File

@@ -1,15 +0,0 @@
Copyright [2014] [wisemapping]
Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
"powered by wisemapping" text requirement on every single page;
you may not use this file except in compliance with the License.
You may obtain a copy of the license at
http://www.wisemapping.org/license
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

155
pom.xml
View File

@@ -1,155 +0,0 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<properties>
<com.wisemapping.version>5.0.10</com.wisemapping.version>
<superpom.dir>${project.basedir}/wise-webapps</superpom.dir>
</properties>
<scm>
<developerConnection>scm:git:git@bitbucket.org:wisemapping/wisemapping-open-source.git</developerConnection>
</scm>
<modelVersion>4.0.0</modelVersion>
<groupId>org.wisemapping</groupId>
<artifactId>wisemapping</artifactId>
<name>WiseMapping Project</name>
<version>5.0.10</version>
<packaging>pom</packaging>
<licenses>
<license>
<name>WiseMapping Public License Version 1.0</name>
<url>http://www.wisemapping.org/wisemapping-public-license-version-1-0-wpl</url>
<comments>A business-friendly OSS license</comments>
</license>
</licenses>
<pluginRepositories>
<pluginRepository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Maven 2 Repository</name>
<url>http://download.java.net/maven/2/</url>
<layout>default</layout>
</pluginRepository>
</pluginRepositories>
<organization>
<name>WiseMapping</name>
<url>http://www.wisemapping.org/</url>
</organization>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.12</version>
</plugin>
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<version>1.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>native2ascii-maven-plugin</artifactId>
<version>1.0-beta-1</version>
</plugin>
<plugin>
<groupId>com.github.searls</groupId>
<artifactId>jasmine-maven-plugin</artifactId>
<version>1.3.1.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.2</version>
<configuration>
<descriptors>
<descriptor>distribution/assembly/standalone-editor.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
<site>
<id>www.wisemapping.org</id>
<url>scp://www.wisemapping.org/docs/project/</url>
</site>
</distributionManagement>
<!-- Module Dependencies -->
<modules>
<module>wise-ui</module>
<module>wise-webapp</module>
</modules>
</project>

7
wise-api/Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
FROM amazoncorretto:21.0.2
LABEL maintainer="Paulo Gustavo Veiga <pveiga@wisemapping.com>"
VOLUME /tmp
COPY target/wisemapping-api.jar wisemapping-api.jar
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /wisemapping-api.jar ${0} ${@}"]

View File

@@ -37,6 +37,6 @@ Template Path: /service/admin/users/{userId}/password
Creating a new user:
* Template Path: /service/admin/users/
* Method: Post
* curl "http://{host.name}:{host.port}/{context.path}/service/admin/users" --request POST --basic -u "admin@wisemapping.org:test" -H "Content-Type:application/json" --data '{"email": "te2@mydomain.de", "lastname": "lastname", "firstname":"myfirstname","password":"password"}'
* curl "http://{host.name}:{host.port}/{context.path}/service/admin/users/" --request POST --basic -u "admin@wisemapping.org:test" -H "Content-Type:application/json" --data '{"email": "te2@mydomain.de", "lastname": "lastname", "firstname":"myfirstname","password":"password"}'

232
wise-api/pom.xml Normal file
View File

@@ -0,0 +1,232 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
</parent>
<groupId>org.wisemapping</groupId>
<artifactId>wise-api</artifactId>
<version>6.0.0-SNAPSHOT</version>
<name>WiseMapping API</name>
<url>https://www.wisemapping.org</url>
<properties>
<com.wisemapping.version>6.0.0-SNAPSHOT</com.wisemapping.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>6.1.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.intellij</groupId>
<artifactId>annotations</artifactId>
<version>12.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.3</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.1.Final</version>
</dependency>
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.4.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.7</version>
</dependency>
<!-- Connection Pool-->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.1.0</version>
</dependency>
<!-- Only for test purposes -->
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.7.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.4</version>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>4.5.14</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>6.2.1</version>
<scope>test</scope>
</dependency>
<!-- JWT dependencies -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<finalName>wisemapping-api</finalName>
</configuration>
</execution>
</executions>
<!-- <configuration>-->
<!-- <jvmArguments>-->
<!-- -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005-->
<!-- </jvmArguments>-->
<!-- </configuration>-->
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>https://repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
</project>

View File

@@ -0,0 +1,26 @@
package com.wisemapping;
import com.wisemapping.config.common.CommonConfig;
import com.wisemapping.config.rest.RestAppConfig;
import com.wisemapping.config.rest.WebConfig;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.security.web.firewall.StrictHttpFirewall;
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder()
.parent(CommonConfig.class).web(WebApplicationType.NONE)
.child(RestAppConfig.class, WebConfig.class).web(WebApplicationType.SERVLET)
.run(args);
}
@Bean
public StrictHttpFirewall httpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowSemicolon(true);
return firewall;
}
}

View File

@@ -0,0 +1,48 @@
package com.wisemapping.config.common;
import com.wisemapping.dao.LabelManagerImpl;
import com.wisemapping.model.Account;
import com.wisemapping.security.AuthenticationProvider;
import com.wisemapping.security.Utils;
import com.wisemapping.service.MindmapServiceImpl;
import com.wisemapping.util.VelocityEngineUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import java.util.Locale;
@ComponentScan(basePackageClasses = {AuthenticationProvider.class, MindmapServiceImpl.class, LabelManagerImpl.class, VelocityEngineUtils.class})
@Import({JPAConfig.class, SecurityConfig.class})
@EnableAutoConfiguration
public class CommonConfig {
@Bean
public LocaleResolver localeResolver() {
return new AcceptHeaderLocaleResolver() {
@Override
public Locale resolveLocale(@NotNull HttpServletRequest request) {
final Account user = Utils.getUser();
Locale result;
if (user != null && user.getLocale() != null) {
String locale = user.getLocale();
final String locales[] = locale.split("_");
Locale.Builder builder = new Locale.Builder().setLanguage(locales[0]);
if (locales.length > 1) {
builder.setVariant(locales[1]);
}
result = builder.build();
} else {
result = super.resolveLocale(request);
}
return result;
}
};
}
}

View File

@@ -0,0 +1,16 @@
package com.wisemapping.config.common;
import com.wisemapping.dao.MindmapManagerImpl;
import com.wisemapping.model.Account;
import com.wisemapping.service.MindmapServiceImpl;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@Configuration
@EnableJpaRepositories(basePackageClasses={MindmapServiceImpl.class, MindmapManagerImpl.class})
@EntityScan(basePackageClasses= Account.class)
public class JPAConfig {
}

View File

@@ -0,0 +1,76 @@
package com.wisemapping.config.common;
import com.wisemapping.security.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(
securedEnabled = true,
jsr250Enabled = true)
public class SecurityConfig {
@Autowired
private ReadSecurityAdvise readAdvice;
@Autowired
private UpdateSecurityAdvise updateAdvice;
@Autowired
private UserDetailsService userDetailsService;
@Bean
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler =
new DefaultMethodSecurityExpressionHandler();
final MapAccessPermissionEvaluation permissionEvaluator = new MapAccessPermissionEvaluation(readAdvice, updateAdvice);
expressionHandler.setPermissionEvaluator(permissionEvaluator);
return expressionHandler;
}
@Bean
public PasswordEncoder passwordEncoder() {
return DefaultPasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
public AuthenticationProvider googleAuthenticationProvider() {
return new GoogleAuthenticationProvider(userDetailsService);
}
@Bean
public AuthenticationProvider dbAuthenticationProvider() {
final com.wisemapping.security.AuthenticationProvider provider =
new com.wisemapping.security.AuthenticationProvider();
provider.setEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}
@Bean
public AuthenticationManager authenticationManager(@NotNull HttpSecurity http)
throws Exception {
final AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
builder.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
builder.authenticationProvider(dbAuthenticationProvider());
builder.authenticationProvider(googleAuthenticationProvider());
return builder.build();
}
}

View File

@@ -0,0 +1,71 @@
package com.wisemapping.config.rest;
import com.wisemapping.filter.JwtAuthenticationFilter;
import com.wisemapping.rest.MindmapController;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
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 org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import static org.springframework.security.config.Customizer.withDefaults;
@SpringBootApplication(scanBasePackageClasses = {MindmapController.class, JwtAuthenticationFilter.class})
@EnableWebSecurity
public class RestAppConfig {
@Value("${app.api.http-basic-enabled:false}")
private boolean enableHttpBasic;
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
@Bean
SecurityFilterChain apiSecurityFilterChain(@NotNull final HttpSecurity http, @NotNull final MvcRequestMatcher.Builder mvc) throws Exception {
http
.securityMatcher("/**")
.addFilterAfter(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(auth -> auth
.requestMatchers(mvc.pattern("/error")).permitAll()
.requestMatchers(mvc.pattern("/api/restful/authenticate")).permitAll()
.requestMatchers(mvc.pattern("/api/restful/users/")).permitAll()
.requestMatchers(mvc.pattern("/api/restful/app/config")).permitAll()
.requestMatchers(mvc.pattern("/api/restful/maps/*/metadata")).permitAll()
.requestMatchers(mvc.pattern("/api/restful/maps/*/document/xml-pub")).permitAll()
.requestMatchers(mvc.pattern("/api/restful/users/resetPassword")).permitAll()
.requestMatchers(mvc.pattern("/api/restful/oauth2/googlecallback")).permitAll()
.requestMatchers(mvc.pattern("/api/restful/oauth2/confirmaccountsync")).permitAll()
.requestMatchers(mvc.pattern("/api/restful/admin/**")).hasAnyRole("ADMIN")
.requestMatchers(mvc.pattern("/**")).hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
)
.logout(logout -> logout.permitAll()
.logoutSuccessHandler((request, response, authentication) -> {
response.setStatus(HttpServletResponse.SC_OK);
}))
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
// Http basic is mainly used by automation tests.
if (enableHttpBasic) {
http.httpBasic(withDefaults());
}
return http.build();
}
}

View File

@@ -0,0 +1,27 @@
package com.wisemapping.config.rest;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Value("${app.security.corsAllowedOrigins:}")
private String corsAllowedOrigins;
@Override
public void addCorsMappings(@NotNull CorsRegistry registry) {
if (!corsAllowedOrigins.isEmpty()) {
registry.addMapping("/api/**")
.exposedHeaders("*")
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins(corsAllowedOrigins)
.maxAge(3600);
}
}
}

View File

@@ -0,0 +1,26 @@
package com.wisemapping.dao;
import com.wisemapping.model.MindmapLabel;
import com.wisemapping.model.Account;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface LabelManager {
void addLabel(@NotNull final MindmapLabel label);
void saveLabel(@NotNull final MindmapLabel label);
@NotNull
List<MindmapLabel> getAllLabels(@NotNull final Account user);
@Nullable
MindmapLabel getLabelById(int id, @NotNull final Account user);
@Nullable
MindmapLabel getLabelByTitle(@NotNull final String title, @NotNull final Account user);
void removeLabel(@NotNull final MindmapLabel label);
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.dao;
import com.wisemapping.model.MindmapLabel;
import com.wisemapping.model.Account;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository("labelManager")
public class LabelManagerImpl
implements LabelManager {
@Autowired
private EntityManager entityManager;
@Override
public void addLabel(@NotNull final MindmapLabel label) {
saveLabel(label);
}
@Override
public void saveLabel(@NotNull final MindmapLabel label) {
entityManager.persist(label);
}
@NotNull
@Override
public List<MindmapLabel> getAllLabels(@NotNull final Account user) {
final TypedQuery<MindmapLabel> query = entityManager.createQuery("from com.wisemapping.model.MindmapLabel wisemapping where creator=:creatorId", MindmapLabel.class);
query.setParameter("creatorId", user);
return query.getResultList();
}
@Nullable
@Override
public MindmapLabel getLabelById(int id, @NotNull final Account user) {
final TypedQuery<MindmapLabel> query = entityManager.createQuery("from com.wisemapping.model.MindmapLabel wisemapping where id=:id and creator=:creator", MindmapLabel.class);
query.setParameter("id", id);
query.setParameter("creator", user);
final List<MindmapLabel> resultList = query.getResultList();
return getFirst(resultList);
}
@Nullable
@Override
public MindmapLabel getLabelByTitle(@NotNull String title, @NotNull final Account user) {
final TypedQuery<MindmapLabel> query = entityManager.createQuery("from com.wisemapping.model.MindmapLabel wisemapping where title=:title and creator=:creator", MindmapLabel.class);
query.setParameter("title", title);
query.setParameter("creator", user);
return query.getResultList().stream().findFirst().orElse(null);
}
@Override
public void removeLabel(@NotNull MindmapLabel label) {
entityManager.remove(label);
}
@Nullable
private MindmapLabel getFirst(final List<MindmapLabel> labels) {
MindmapLabel result = null;
if (labels != null && !labels.isEmpty()) {
result = labels.get(0);
}
return result;
}
}

View File

@@ -22,31 +22,22 @@ import com.wisemapping.model.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.List;
public interface MindmapManager {
Collaborator findCollaborator(@NotNull String email);
Collaborator findCollaborator(int id);
List<Collaboration> findCollaboration(final int collaboratorId);
List<Collaboration> findCollaboration(final CollaborationRole userRole);
Collaboration findCollaboration(final int mindmapId, final User user);
List<Mindmap> getAllMindmaps();
@Nullable
Mindmap getMindmapById(int mindmapId);
Mindmap getMindmapByTitle(final String name, final User user);
Mindmap getMindmapByTitle(final String name, final Account user);
void addCollaborator(Collaborator collaborator);
void addMindmap(User user, Mindmap mindmap);
void addMindmap(Account user, Mindmap mindmap);
void saveMindmap(Mindmap mindmap);
@@ -58,17 +49,11 @@ public interface MindmapManager {
void removeCollaboration(Collaboration collaboration);
List<Mindmap> search(MindMapCriteria criteria);
List<Mindmap> search(MindMapCriteria criteria, int maxResult);
List<MindMapHistory> getHistoryFrom(int mindmapId);
MindMapHistory getHistory(int historyId);
void updateCollaboration(@NotNull Collaboration collaboration);
void purgeHistory(int mapId) throws IOException;
List<Mindmap> findMindmapByUser(User user);
List<Mindmap> findMindmapByUser(Account user);
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.dao;
import com.wisemapping.model.*;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Calendar;
import java.util.List;
@Repository("mindmapManager")
public class MindmapManagerImpl
implements MindmapManager {
@Autowired
private EntityManager entityManager;
@Override
public Collaborator findCollaborator(@NotNull final String email) {
final Collaborator collaborator;
final TypedQuery<Collaborator> query = entityManager.createQuery("from com.wisemapping.model.Collaborator collaborator where email=:email", Collaborator.class);
query.setParameter("email", email);
final List<Collaborator> collaborators = query.getResultList();
if (collaborators != null && !collaborators.isEmpty()) {
assert collaborators.size() == 1 : "More than one user with the same email!";
collaborator = collaborators.get(0);
} else {
collaborator = null;
}
return collaborator;
}
@Override
public List<MindMapHistory> getHistoryFrom(int mindmapId) {
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final CriteriaQuery<MindMapHistory> cr = cb.createQuery(MindMapHistory.class);
final Root<MindMapHistory> root = cr.from(MindMapHistory.class);
final CriteriaQuery<MindMapHistory> select = cr.select(root)
.where(cb.equal(root.get("mindmapId"), mindmapId))
.orderBy(cb.desc(root.get("creationTime")));
return entityManager.
createQuery(select)
.setMaxResults(30)
.getResultList();
}
@Override
public MindMapHistory getHistory(int historyId) {
return entityManager.find(MindMapHistory.class, historyId);
}
@Override
public void updateCollaboration(@NotNull Collaboration collaboration) {
entityManager.persist(collaboration);
}
@Override
public List<Mindmap> findMindmapByUser(@NotNull Account user) {
final TypedQuery<Mindmap> query = entityManager
.createQuery("from com.wisemapping.model.Mindmap m where m.id in (select c.mindMap.id from com.wisemapping.model.Collaboration as c where c.collaborator.id=:collabId )", Mindmap.class);
query.setParameter("collabId", user.getId());
return query.getResultList();
}
@Override
public List<Collaboration> findCollaboration(final int collaboratorId) {
final TypedQuery<Collaboration> query = entityManager.createQuery("from com.wisemapping.model.Collaboration c where c.collaborator.id=:collaboratorId", Collaboration.class);
query.setParameter("collaboratorId", collaboratorId);
return query.getResultList();
}
@Override
public void addCollaborator(@NotNull Collaborator collaborator) {
assert collaborator != null : "ADD MINDMAP COLLABORATOR: Collaborator is required!";
entityManager.persist(collaborator);
}
@Override
public void removeCollaboration(Collaboration collaboration) {
entityManager.remove(collaboration);
}
@Override
public void removeCollaborator(@NotNull Collaborator collaborator) {
entityManager.remove(collaborator);
}
@Override
@Nullable
public Mindmap getMindmapById(int id) {
return entityManager.find(Mindmap.class, id);
}
@Override
public Mindmap getMindmapByTitle(final String title, final Account user) {
final TypedQuery<Mindmap> query = entityManager.createQuery("from com.wisemapping.model.Mindmap wisemapping where title=:title and creator=:creator", Mindmap.class);
query.setParameter("title", title);
query.setParameter("creator", user);
List<Mindmap> mindMaps = query.getResultList();
Mindmap result = null;
if (mindMaps != null && !mindMaps.isEmpty()) {
result = mindMaps.get(0);
}
return result;
}
@Override
public void addMindmap(Account user, Mindmap mindMap) {
saveMindmap(mindMap);
}
@Override
public void saveMindmap(Mindmap mindMap) {
assert mindMap != null : "Save Mindmap: Mindmap is required!";
entityManager.persist(mindMap);
}
@Override
public void updateMindmap(@NotNull Mindmap mindMap, boolean saveHistory) {
assert mindMap != null : "Save Mindmap: Mindmap is required!";
entityManager.merge(mindMap);
if (saveHistory) {
saveHistory(mindMap);
}
}
@Override
public void removeMindmap(@NotNull final Mindmap mindmap) {
// Delete history first ...
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final CriteriaDelete<MindMapHistory> cr = cb.createCriteriaDelete(MindMapHistory.class);
final Root<MindMapHistory> root = cr.from(MindMapHistory.class);
final CriteriaDelete<MindMapHistory> deleteStatement = cr.where(cb.equal(root.get("mindmapId"), mindmap.getId()));
entityManager.createQuery(deleteStatement).executeUpdate();
// Remove collaborations ...
mindmap.removedCollaboration(mindmap.getCollaborations());
// Delete mindmap ....
entityManager.remove(mindmap);
}
private void saveHistory(@NotNull final Mindmap mindMap) {
final MindMapHistory history = new MindMapHistory();
history.setZippedXml(mindMap.getZippedXml());
history.setCreationTime(Calendar.getInstance());
history.setEditor(mindMap.getLastEditor());
history.setMindmapId(mindMap.getId());
entityManager.merge(history);
}
}

View File

@@ -20,31 +20,31 @@ package com.wisemapping.dao;
import com.wisemapping.model.AccessAuditory;
import com.wisemapping.model.Collaborator;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public interface UserManager {
List<User> getAllUsers();
List<Account> getAllUsers();
User getUserBy(String email);
Account getUserBy(String email);
User getUserBy(int id);
Account getUserBy(int id);
void createUser(User user);
void createUser(Account user);
void auditLogin(@NotNull AccessAuditory accessAuditory);
void updateUser(User user);
void updateUser(Account user);
User getUserByActivationCode(long code);
Account getUserByActivationCode(long code);
Collaborator getCollaboratorBy(String email);
User createUser(User user, Collaborator col);
Account createUser(Account user, Collaborator col);
void removeUser(@NotNull User user);
void removeUser(@NotNull Account user);
}

View File

@@ -18,47 +18,49 @@
package com.wisemapping.dao;
import com.wisemapping.model.AccessAuditory;
import com.wisemapping.model.Collaboration;
import com.wisemapping.model.Collaborator;
import com.wisemapping.model.User;
import com.wisemapping.model.*;
import com.wisemapping.security.DefaultPasswordEncoderFactories;
import com.wisemapping.security.LegacyPasswordEncoder;
import org.hibernate.ObjectNotFoundException;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
@Repository
public class UserManagerImpl
extends HibernateDaoSupport
implements UserManager {
@Autowired
private EntityManager entityManager;
@Autowired
private PasswordEncoder passwordEncoder;
public UserManagerImpl() {
}
public void setEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
@SuppressWarnings("unchecked")
public List<User> getAllUsers() {
return currentSession().createQuery("from com.wisemapping.model.User user").list();
public List<Account> getAllUsers() {
return entityManager.createQuery("from com.wisemapping.model.Account user", Account.class).getResultList();
}
@Override
public User getUserBy(@NotNull final String email) {
User user = null;
@Nullable
public Account getUserBy(@NotNull final String email) {
Account user = null;
var query = currentSession().createQuery("from com.wisemapping.model.User colaborator where email=:email");
TypedQuery<Account> query = entityManager.createQuery("from com.wisemapping.model.Account colaborator where email=:email", Account.class);
query.setParameter("email", email);
final List<User> users = query.list();
final List<Account> users = query.getResultList();
if (users != null && !users.isEmpty()) {
assert users.size() == 1 : "More than one user with the same email!";
user = users.get(0);
@@ -69,80 +71,73 @@ public class UserManagerImpl
@Override
public Collaborator getCollaboratorBy(final String email) {
final Collaborator cola;
var query = currentSession().createQuery("from com.wisemapping.model.Collaborator colaborator where " +
"email=:email");
final Collaborator result;
final TypedQuery<Collaborator> query = entityManager.createQuery("from com.wisemapping.model.Collaborator colaborator where " +
"email=:email", Collaborator.class);
query.setParameter("email", email);
final List<User> cols = query.list();
final List<Collaborator> cols = query.getResultList();
if (cols != null && !cols.isEmpty()) {
assert cols.size() == 1 : "More than one colaborator with the same email!";
cola = cols.get(0);
result = cols.get(0);
} else {
cola = null;
result = null;
}
return cola;
return result;
}
@Nullable
@Override
public User getUserBy(int id) {
User user = null;
try {
user = getHibernateTemplate().get(User.class, id);
} catch (ObjectNotFoundException e) {
// Ignore ...
}
return user;
public Account getUserBy(int id) {
return entityManager.find(Account.class, id);
}
@Override
public void createUser(User user) {
public void createUser(Account user) {
assert user != null : "Trying to store a null user";
user.setPassword(passwordEncoder.encode(user.getPassword()));
getHibernateTemplate().saveOrUpdate(user);
if (!AuthenticationType.GOOGLE_OAUTH2.equals(user.getAuthenticationType())) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
} else {
user.setPassword("");
}
entityManager.persist(user);
}
@Override
public User createUser(@NotNull User user, @NotNull Collaborator collaborator) {
public Account createUser(@NotNull Account user, @NotNull Collaborator collaborator) {
assert user != null : "Trying to store a null user";
// Migrate from previous temporal collab to new user ...
List<Collaboration> newCollabs = new ArrayList<>();
final Set<Collaboration> collaborations = collaborator.getCollaborations();
for (Collaboration oldCollab : collaborations) {
Collaboration newCollab = new Collaboration();
newCollab.setRoleId(oldCollab.getRole().ordinal());
newCollab.setMindMap(oldCollab.getMindMap());
newCollab.setCollaborator(user);
user.addCollaboration(newCollab);
newCollabs.add(newCollab);
}
// Delete old collaboration
final HibernateTemplate template = getHibernateTemplate();
collaborations.forEach(c -> template.delete(c));
template.delete(collaborator);
template.flush();
collaborator.setEmail(collaborator.getEmail() + "_toRemove");
entityManager.merge(collaborator);
entityManager.flush();
// Save all new...
this.createUser(user);
newCollabs.forEach(c -> template.saveOrUpdate(c));
// Update mindmap ...
final Set<Collaboration> collaborations = new CopyOnWriteArraySet<>(collaborator.getCollaborations());
for (Collaboration collabs : collaborations) {
collabs.setCollaborator(user);
}
// Delete old user ...
entityManager.remove(collaborator);
return user;
}
@Override
public void removeUser(@NotNull final User user) {
getHibernateTemplate().delete(user);
public void removeUser(@NotNull final Account user) {
entityManager.remove(user);
}
public void auditLogin(@NotNull AccessAuditory accessAuditory) {
assert accessAuditory != null : "accessAuditory is null";
getHibernateTemplate().save(accessAuditory);
entityManager.persist(accessAuditory);
}
public void updateUser(@NotNull User user) {
public void updateUser(@NotNull Account user) {
assert user != null : "user is null";
// Does the password need to be encrypted ?
@@ -151,21 +146,21 @@ public class UserManagerImpl
user.setPassword(passwordEncoder.encode(user.getPassword()));
}
getHibernateTemplate().update(user);
entityManager.merge(user);
}
public User getUserByActivationCode(long code) {
final User user;
public Account getUserByActivationCode(long code) {
final Account user;
var query = currentSession().createQuery("from com.wisemapping.model.User user where " +
"activationCode=:activationCode");
final TypedQuery<Account> query = entityManager.createQuery("from com.wisemapping.model.User user where " +
"activationCode=:activationCode", Account.class);
query.setParameter("activationCode", code);
final List users = query.list();
final List<Account> users = query.getResultList();
if (users != null && !users.isEmpty()) {
assert users.size() == 1 : "More than one user with the same username!";
user = (User) users.get(0);
user = users.get(0);
} else {
user = null;
}

View File

@@ -19,7 +19,6 @@
package com.wisemapping.exceptions;
import com.wisemapping.model.Collaborator;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
public class AccessDeniedSecurityException
@@ -31,7 +30,7 @@ public class AccessDeniedSecurityException
}
public AccessDeniedSecurityException(@NotNull long mapId, Collaborator user) {
super("No enough permissions to access map. Id: " + mapId + ", User: " + user, Severity.FATAL);
super("You do not have enough right access to see this map. This map has been changed to private or deleted.", Severity.FATAL);
}
@NotNull

View File

@@ -21,7 +21,7 @@ package com.wisemapping.exceptions;
import org.springframework.lang.Nullable;
import javax.validation.constraints.NotNull;
import jakarta.validation.constraints.NotNull;
public class InvalidEmailException
extends ClientException {

View File

@@ -21,7 +21,7 @@ package com.wisemapping.exceptions;
import org.springframework.lang.Nullable;
import javax.validation.constraints.NotNull;
import jakarta.validation.constraints.NotNull;
public class InvalidMindmapException
extends ClientException {

View File

@@ -19,7 +19,7 @@
package com.wisemapping.exceptions;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import com.wisemapping.service.LockManager;
import org.jetbrains.annotations.NotNull;
@@ -32,7 +32,7 @@ public class LockException
super(message, Severity.INFO);
}
public static LockException createLockLost(@NotNull Mindmap mindmap, @NotNull User user, @NotNull LockManager manager) {
public static LockException createLockLost(@NotNull Mindmap mindmap, @NotNull Account user, @NotNull LockManager manager) {
return new LockException("Lock can not be granted to " + user.getEmail() + ". The lock is assigned to " + manager.getLockInfo(mindmap));
}

View File

@@ -19,7 +19,7 @@
package com.wisemapping.exceptions;
import javax.validation.constraints.NotNull;
import jakarta.validation.constraints.NotNull;
public class MapCouldNotFoundException
extends ClientException

View File

@@ -20,11 +20,11 @@ package com.wisemapping.exceptions;
import org.jetbrains.annotations.NotNull;
public class MapNonPublicException
public class MapNotPublicSecurityException
extends ClientException {
public static final String MSG_KEY = "ACCESS_HAS_BEEN_REVOKED";
public MapNonPublicException(@NotNull String msg) {
public MapNotPublicSecurityException(@NotNull String msg) {
super(msg, Severity.FATAL);
}

View File

@@ -0,0 +1,13 @@
package com.wisemapping.exceptions;
import com.wisemapping.service.google.http.HttpInvokerException;
import jakarta.validation.constraints.NotNull;
public class OAuthAuthenticationException extends WiseMappingException {
public OAuthAuthenticationException(@NotNull HttpInvokerException exception) {
super(exception.getMessage());
}
}

View File

@@ -1,38 +1,39 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.exceptions;
import org.jetbrains.annotations.NotNull;
public class MultipleSessionsOpenException
extends ClientException
{
private static final String MSG_KEY = "MINDMAP_OUTDATED_BY_YOU";
public MultipleSessionsOpenException(@NotNull String techInfo)
{
super(techInfo,Severity.INFO);
}
@NotNull
@Override
protected String getMsgBundleKey() {
return MSG_KEY;
}
}
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.exceptions;
import org.jetbrains.annotations.NotNull;
public class OwnerCannotChangeException
extends ClientException
{
private static final String MSG_KEY = "OWNER_ROLE_CAN_NOT_BE_CHANGED";
public OwnerCannotChangeException(@NotNull String email)
{
super("Collab email can not be change. " + email + " is the the owner.",Severity.WARNING);
}
@NotNull
@Override
protected String getMsgBundleKey() {
return MSG_KEY;
}
}

View File

@@ -1,44 +1,37 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
public class CSFRRequestMatcher implements RequestMatcher {
private String prefix;
static String[] supportedMethods = {"POST", "PUT", "GET", "DELETE", "PATCH"};
@Override
public boolean matches(HttpServletRequest request) {
final String requestURI = request.getRequestURI();
return Arrays.stream(supportedMethods).anyMatch(p -> request.getMethod().toUpperCase().equals(p))
&& requestURI.startsWith(prefix);
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.exceptions;
import jakarta.validation.constraints.NotNull;
public class PasswordTooLongException
extends ClientException {
private static final String PASSWORD_TOO_LONG = "PASSWORD_TOO_LONG";
public PasswordTooLongException() {
super("Password length must be less than 40 characters", Severity.WARNING);
}
@NotNull
@Override
protected String getMsgBundleKey() {
return PASSWORD_TOO_LONG;
}
}

View File

@@ -18,15 +18,15 @@
package com.wisemapping.exceptions;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import org.jetbrains.annotations.NotNull;
public class SessionExpiredException
extends ClientException {
private static final String MSG_KEY = "MINDMAP_TIMESTAMP_OUTDATED";
private final User lastUpdater;
private final Account lastUpdater;
public SessionExpiredException(@NotNull String debugInfo, @NotNull User lastUpdater) {
public SessionExpiredException(@NotNull String debugInfo, @NotNull Account lastUpdater) {
super(debugInfo, Severity.FATAL);
this.lastUpdater = lastUpdater;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.exceptions;
import jakarta.validation.constraints.NotNull;
public class TooManyInactiveAccountsExceptions
extends ClientException {
private static final String TOO_MANY_INACTIVE_ACCOUNTS = "TOO_MANY_INACTIVE_ACCOUNTS";
public TooManyInactiveAccountsExceptions(@NotNull long accounts) {
super("Too many inactive accounts:" + accounts, Severity.WARNING);
}
@NotNull
@Override
protected String getMsgBundleKey() {
return TOO_MANY_INACTIVE_ACCOUNTS;
}
}

View File

@@ -16,7 +16,7 @@
* limitations under the License.
*/
package com.wisemapping.rest;
package com.wisemapping.exceptions;
import com.wisemapping.exceptions.WiseMappingException;

View File

@@ -0,0 +1,87 @@
package com.wisemapping.filter;
import com.wisemapping.security.JwtTokenUtil;
import com.wisemapping.security.UserDetails;
import com.wisemapping.security.UserDetailsService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Optional;
import static com.wisemapping.security.JwtTokenUtil.BEARER_TOKEN_PREFIX;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
final private static Logger logger = LogManager.getLogger();
@Override
protected void doFilterInternal(@NotNull final HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain)
throws ServletException, IOException {
final Optional<String> token = getJwtTokenFromRequest(request);
if (token.isPresent() && SecurityContextHolder.getContext().getAuthentication() == null) {
// Extract email from token ...
final Optional<String> email = extractEmailFromToken(token.get());
if (email.isPresent() && jwtTokenUtil.validateJwtToken(token.get())) {
// Is it an existing user ?
try {
final UserDetails userDetails = userDetailsService.loadUserByUsername(email.get());
final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
} catch (UsernameNotFoundException e) {
logger.trace("User " + email.get() + " could not be found");
}
}
}
filterChain.doFilter(request, response);
}
private Optional<String> extractEmailFromToken(final @NotNull String token) {
Optional<String> result = Optional.empty();
try {
result = Optional.ofNullable(jwtTokenUtil.extractFromJwtToken(token));
} catch (Exception e) {
// Handle token extraction/validation errors
logger.debug("Error extracting email from token: " + e.getMessage());
}
logger.trace("JWT token email:" + result);
return result;
}
private static Optional<String> getJwtTokenFromRequest(@NotNull HttpServletRequest request) {
Optional<String> result = Optional.empty();
final String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (authorizationHeader != null) {
if (authorizationHeader.startsWith(BEARER_TOKEN_PREFIX)) {
logger.trace("JWT Bearer token found.");
final String token = authorizationHeader.substring(BEARER_TOKEN_PREFIX.length());
result = Optional.of(token);
}
}
return result;
}
}

View File

@@ -20,21 +20,23 @@ package com.wisemapping.listener;
import com.wisemapping.exceptions.AccessDeniedSecurityException;
import com.wisemapping.exceptions.LockException;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import com.wisemapping.security.Utils;
import com.wisemapping.service.LockManager;
import com.wisemapping.service.MindmapService;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
public class UnlockOnExpireListener implements HttpSessionListener {
private static final Logger logger = Logger.getLogger(UnlockOnExpireListener.class);
private static final Logger logger = LogManager.getLogger();
@Override
public void sessionCreated(@NotNull HttpSessionEvent event) {
@@ -49,7 +51,7 @@ public class UnlockOnExpireListener implements HttpSessionListener {
final MindmapService mindmapService = (MindmapService) wc.getBean("mindmapService");
final LockManager lockManager = mindmapService.getLockManager();
final User user = Utils.getUser(false);
final Account user = Utils.getUser(false);
if (user != null) {
synchronized (mindmapService.getLockManager()) {
try {

View File

@@ -20,7 +20,7 @@ package com.wisemapping.model;
import org.jetbrains.annotations.NotNull;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Calendar;
@@ -38,7 +38,7 @@ public class AccessAuditory
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = true)
private User user = null;
private Account user = null;
public AccessAuditory() {
}
@@ -59,11 +59,11 @@ public class AccessAuditory
return loginDate;
}
public void setUser(@NotNull User user) {
public void setUser(@NotNull Account user) {
this.user = user;
}
public User getUser() {
public Account getUser() {
return this.user;
}
}

View File

@@ -21,19 +21,20 @@ package com.wisemapping.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "USER")
@PrimaryKeyJoinColumn(name = "colaborator_id")
public class User
@Table(name = "ACCOUNT")
@PrimaryKeyJoinColumn(name = "collaborator_id")
public class Account
extends Collaborator
implements Serializable {
public static final int MAX_PASSWORD_LENGTH_SIZE = 40;
private String firstname;
private String lastname;
private String password;
@@ -54,20 +55,16 @@ public class User
@Column(name = "authenticator_uri")
private String authenticatorUri;
@ElementCollection
@CollectionTable(name = "TAG", joinColumns = @JoinColumn(name = "user_id"))
@Column(name = "name")
private Set<String> tags = new HashSet<>();
@Column(name = "google_sync")
private Boolean googleSync;
public User() {
}
@Column(name = "sync_code")
private String syncCode;
public void setTags(Set<String> tags) {
this.tags = tags;
}
@Column(name = "google_token")
private String googleToken;
public Set<String> getTags() {
return tags;
public Account() {
}
public String getFullName() {
@@ -94,7 +91,7 @@ public class User
return password;
}
public void setPassword(String password) {
public void setPassword(@jakarta.validation.constraints.NotNull String password) {
this.password = password;
}
@@ -163,6 +160,34 @@ public class User
this.authenticatorUri = authenticatorUri;
}
public void setAuthenticationTypeCode(Character authenticationTypeCode) {
this.authenticationTypeCode = authenticationTypeCode;
}
public Boolean getGoogleSync() {
return googleSync != null && googleSync;
}
public void setGoogleSync(Boolean googleSync) {
this.googleSync = googleSync;
}
public String getSyncCode() {
return syncCode;
}
public void setSyncCode(String syncCode) {
this.syncCode = syncCode;
}
public String getGoogleToken() {
return googleToken;
}
public void setGoogleToken(String googleToken) {
this.googleToken = googleToken;
}
@Override
public String toString() {
return "User{" +

View File

@@ -23,7 +23,8 @@ import org.jetbrains.annotations.NotNull;
public enum AuthenticationType {
DATABASE('D'),
LDAP('L'),
OPENID('O');
GOOGLE_OAUTH2('G');
private final char schemaCode;
AuthenticationType(char schemaCode) {

View File

@@ -19,12 +19,12 @@
package com.wisemapping.model;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.jetbrains.annotations.Nullable;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Objects;
@Entity
@Table(name = "COLLABORATION")
@@ -33,7 +33,6 @@ public class Collaboration implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
;
@Column(name = "role_id", unique = true)
private CollaborationRole role;
@@ -43,11 +42,11 @@ public class Collaboration implements Serializable {
private Mindmap mindMap;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "colaborator_id", nullable = false)
@JoinColumn(name = "collaborator_id", nullable = false)
private Collaborator collaborator;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "properties_id", nullable = false, unique = true)
@JoinColumn(name = "properties_id", nullable = true, unique = true)
private CollaborationProperties collaborationProperties = new CollaborationProperties();
public Collaboration() {
@@ -104,12 +103,13 @@ public class Collaboration implements Serializable {
this.collaborator = collaborator;
}
@NotNull
@Nullable
public CollaborationProperties getCollaborationProperties() {
return this.collaborationProperties;
}
public void setCollaborationProperties(@NotNull CollaborationProperties collaborationProperties) {
public void setCollaborationProperties(@Nullable CollaborationProperties collaborationProperties) {
this.collaborationProperties = collaborationProperties;
}
@@ -126,16 +126,14 @@ public class Collaboration implements Serializable {
Collaboration that = (Collaboration) o;
if (id != that.id) return false;
if (collaborator != null ? !collaborator.equals(that.collaborator) : that.collaborator != null) return false;
if (mindMap != null ? !mindMap.equals(that.mindMap) : that.mindMap != null) return false;
if (!Objects.equals(collaborator, that.collaborator)) return false;
if (!Objects.equals(mindMap, that.mindMap)) return false;
return role == that.role;
}
@Override
public int hashCode() {
int result = id ^ (id >>> 32);
result = 31 * result + (role != null ? role.hashCode() : 0);
result = 31 * result + (mindMap != null ? mindMap.hashCode() : 0);
return result;
//https://thorben-janssen.com/ultimate-guide-to-implementing-equals-and-hashcode-with-hibernate/
return 13;
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.model;
import org.jetbrains.annotations.NotNull;
import jakarta.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "COLLABORATION_PROPERTIES")
public class CollaborationProperties implements Serializable {
public static final String DEFAULT_JSON_PROPERTIES = "{\"zoom\":0.8}";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private boolean starred;
@Column(name = "mindmap_properties")
private String mindmapProperties;
public CollaborationProperties() {
}
public boolean getStarred() {
return starred;
}
public void setStarred(boolean starred) {
this.starred = starred;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@NotNull
public String getMindmapProperties() {
return mindmapProperties == null ? DEFAULT_JSON_PROPERTIES : mindmapProperties;
}
public void setMindmapProperties(@NotNull String mindmapProperties) {
this.mindmapProperties = mindmapProperties;
}
}

View File

@@ -1,20 +1,20 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.model;
@@ -22,7 +22,7 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Calendar;
import java.util.HashSet;
@@ -36,14 +36,14 @@ import java.util.Set;
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Collaborator implements Serializable {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String email;
@Column(name = "creation_date")
private Calendar creationDate;
@OneToMany(mappedBy="collaborator")
@OneToMany(mappedBy = "collaborator")
private Set<Collaboration> collaborations = new HashSet<>();
public Collaborator() {
@@ -105,19 +105,26 @@ public class Collaborator implements Serializable {
int id = this.getId();
String email = this.getEmail();
int result = (int) (id ^ (id >>> 32));
int result = id ^ (id >>> 32);
result = 31 * result + (email != null ? email.hashCode() : 0);
return result;
}
public boolean identityEquality(@Nullable Collaborator that) {
if (this == that) return true;
if (that == null) return false;
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (id != that.getId()) {
return false;
}
if (id != that.getId()) return false;
return email != null ? email.equals(that.getEmail()) : that.getEmail() == null;
}
}

View File

@@ -24,7 +24,6 @@ import java.util.List;
public class MindMapCriteria {
private String title;
private String description;
private List<String> tags = new ArrayList<String>();
private boolean orConnector = false;
private int pageNro = 0;
@@ -41,18 +40,9 @@ public class MindMapCriteria {
this.pageNro = page;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@@ -78,8 +68,7 @@ public class MindMapCriteria {
}
public boolean isEmpty() {
return !(getTags() != null && !getTags().isEmpty() || getTitle() != null || getDescription() != null);
return getTitle() != null || getDescription() != null;
}
public static MindMapCriteria EMPTY_CRITERIA = new MindMapCriteria();
}

View File

@@ -22,7 +22,7 @@ import com.wisemapping.util.ZipUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.IOException;
import java.util.Calendar;
@@ -38,7 +38,7 @@ public class MindMapHistory {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "editor_id", nullable = true,unique = false)
private User editor;
private Account editor;
@Column(name = "xml")
private byte[] zippedXml;
@@ -76,11 +76,11 @@ public class MindMapHistory {
}
@Nullable
public User getEditor() {
public Account getEditor() {
return editor;
}
public void setEditor(@Nullable User editor) {
public void setEditor(@Nullable Account editor) {
this.editor = editor;
}

View File

@@ -22,13 +22,15 @@ import com.wisemapping.exceptions.AccessDeniedSecurityException;
import com.wisemapping.exceptions.InvalidMindmapException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.util.ZipUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
@@ -49,29 +51,31 @@ public class Mindmap implements Serializable {
@Column(name = "edition_date")
private Calendar lastModificationTime;
@ManyToOne(fetch = FetchType.LAZY)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "creator_id", unique = true)
private User creator;
private Account creator;
@ManyToOne(fetch = FetchType.LAZY)
@ManyToOne
@JoinColumn(name = "last_editor_id", nullable = false)
@NotFound(action = NotFoundAction.IGNORE)
private User lastEditor;
private Account lastEditor;
private String description;
@Column(name = "public")
private boolean isPublic;
@OneToMany(mappedBy = "mindMap", orphanRemoval = true, cascade = {CascadeType.ALL})
@OneToMany(mappedBy = "mindMap", orphanRemoval = true, cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
private Set<Collaboration> collaborations = new HashSet<>();
@ManyToMany(cascade = CascadeType.ALL)
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE})
@Fetch(FetchMode.JOIN)
@JoinTable(
name = "R_LABEL_MINDMAP",
joinColumns = @JoinColumn(name = "mindmap_id"),
inverseJoinColumns = @JoinColumn(name = "label_id"))
private Set<Label> labels = new LinkedHashSet<>();
private Set<MindmapLabel> labels = new LinkedHashSet<>();
private String title;
@@ -79,13 +83,9 @@ public class Mindmap implements Serializable {
@Basic(fetch = FetchType.LAZY)
private byte[] zippedXml;
//~ Constructors .........................................................................................
public Mindmap() {
}
//~ Methods ..............................................................................................
public void setUnzipXml(@NotNull byte[] value) {
try {
final byte[] zip = ZipUtils.bytesToZip(value);
@@ -142,19 +142,25 @@ public class Mindmap implements Serializable {
}
public void removedCollaboration(@NotNull Collaboration collaboration) {
collaborations.add(collaboration);
// https://stackoverflow.com/questions/25125210/hibernate-persistentset-remove-operation-not-working
this.collaborations.remove(collaboration);
collaboration.setMindMap(null);
}
public void removedCollaboration(@NotNull Set<Collaboration> collaborations) {
this.collaborations.removeAll(collaborations);
}
@NotNull
public Set<Label> getLabels() {
public Set<MindmapLabel> getLabels() {
return labels;
}
public void setLabels(@NotNull final Set<Label> labels) {
public void setLabels(@NotNull final Set<MindmapLabel> labels) {
this.labels = labels;
}
public void addLabel(@NotNull final Label label) {
public void addLabel(@NotNull final MindmapLabel label) {
this.labels.add(label);
}
@@ -177,15 +183,14 @@ public class Mindmap implements Serializable {
return result;
}
public boolean isCreator(@NotNull Account user) {
return this.getCreator() != null && this.getCreator().identityEquality(user);
}
public boolean isPublic() {
return isPublic;
}
//@Todo: This is a hack to overcome some problem with JS EL. For some reason, ${mindmap.public} fails as not supported.
// More research is needed...
public boolean isAccessible() {
return isPublic();
}
public void setPublic(boolean isPublic) {
this.isPublic = isPublic;
@@ -200,11 +205,11 @@ public class Mindmap implements Serializable {
}
@Nullable
public User getLastEditor() {
public Account getLastEditor() {
return lastEditor;
}
public void setLastEditor(@Nullable User lastEditor) {
public void setLastEditor(@Nullable Account lastEditor) {
this.lastEditor = lastEditor;
}
@@ -258,11 +263,11 @@ public class Mindmap implements Serializable {
this.creationTime = creationTime;
}
public void setCreator(@NotNull User creator) {
public void setCreator(@NotNull Account creator) {
this.creator = creator;
}
public User getCreator() {
public Account getCreator() {
return creator;
}
@@ -305,13 +310,19 @@ public class Mindmap implements Serializable {
}
public static String getDefaultMindmapXml(@NotNull final String title) {
return "<map version=\"tango\" theme=\"prism\">" +
"<topic central=\"true\" text=\"" +
escapeXmlAttribute(title) +
"\"/></map>";
}
final StringBuilder result = new StringBuilder();
result.append("<map version=\"tango\">");
result.append("<topic central=\"true\" text=\"");
result.append(StringEscapeUtils.escapeXml(title));
result.append("\"/></map>");
return result.toString();
static private String escapeXmlAttribute(String attValue) {
// Hack: Find out of the box function.
String result = attValue.replace("&", "&amp;");
result = result.replace("<", "&lt;");
result = result.replace("gt", "&gt;");
result = result.replace("\"", "&quot;");
return result;
}
public Mindmap shallowClone() {
@@ -336,7 +347,7 @@ public class Mindmap implements Serializable {
}
public boolean hasLabel(@NotNull final String name) {
for (Label label : this.labels) {
for (MindmapLabel label : this.labels) {
if (label.getTitle().equals(name)) {
return true;
}
@@ -344,19 +355,7 @@ public class Mindmap implements Serializable {
return false;
}
@Nullable
public Label findLabel(int labelId) {
Label result = null;
for (Label label : this.labels) {
if (label.getId() == labelId) {
result = label;
break;
}
}
return result;
}
public void removeLabel(@NotNull final Label label) {
public void removeLabel(@NotNull final MindmapLabel label) {
this.labels.remove(label);
}
}

View File

@@ -22,45 +22,49 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.persistence.*;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Objects;
@Entity
@Table(name = "LABEL")
@Table(name = "MINDMAP_LABEL")
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Label implements Serializable {
public class MindmapLabel implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@NotNull private String title;
@NotNull private String color;
@Nullable private String iconName;
@NotNull
private String title;
@NotNull
private String color;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="creator_id",nullable = true,unique = true)
@NotNull private User creator;
@JoinColumn(name = "creator_id", nullable = true, unique = true)
@NotNull
private Account creator;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="parent_label_id",nullable = true)
@Nullable private Label parent;
@JoinColumn(name = "parent_label_id", nullable = true)
@Nullable
private MindmapLabel parent;
public void setParent(@Nullable Label parent) {
public void setParent(@Nullable MindmapLabel parent) {
this.parent = parent;
}
@Nullable
public Label getParent() {
public MindmapLabel getParent() {
return parent;
}
public void setCreator(@NotNull User creator) {
public void setCreator(@NotNull Account creator) {
this.creator = creator;
}
@NotNull
public User getCreator() {
public Account getCreator() {
return creator;
}
@@ -69,7 +73,7 @@ public class Label implements Serializable {
return title;
}
public void setTitle(@NotNull String title) {
public void setTitle(String title) {
this.title = title;
}
@@ -81,40 +85,30 @@ public class Label implements Serializable {
this.id = id;
}
@NotNull
@Nullable
public String getColor() {
return color;
}
public void setColor(@NotNull String color) {
public void setColor(String color) {
this.color = color;
}
@Nullable
public String getIconName() {
return iconName;
}
public void setIconName(@NotNull String iconName) {
this.iconName = iconName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Label)) return false;
Label label = (Label) o;
if (!(o instanceof MindmapLabel)) return false;
final MindmapLabel label = (MindmapLabel) o;
return id == label.id && creator.getId() == label.creator.getId()
&& !(parent != null ? !parent.equals(label.parent) : label.parent != null);
&& Objects.equals(parent, label.parent);
}
@Override
public int hashCode() {
long result = id;
result = 31 * result + title.hashCode();
result = 31 * result + (creator!=null?creator.hashCode():0);
long result = title.hashCode();
result = 31 * result + (creator != null ? creator.hashCode() : 0);
result = 31 * result + (parent != null ? parent.hashCode() : 0);
return (int) result;
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest;
import com.wisemapping.exceptions.PasswordTooLongException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.Collaboration;
import com.wisemapping.model.MindmapLabel;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.Account;
import com.wisemapping.rest.model.RestUser;
import com.wisemapping.security.Utils;
import com.wisemapping.service.LabelService;
import com.wisemapping.service.MindmapService;
import com.wisemapping.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/restful/account")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
public class AccountController extends BaseController {
@Qualifier("userService")
@Autowired
private UserService userService;
@Qualifier("mindmapService")
@Autowired
private MindmapService mindmapService;
@Qualifier("labelService")
@Autowired
private LabelService labelService;
@RequestMapping(method = RequestMethod.PUT, value = "/password", consumes = {"text/plain"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void changePassword(@RequestBody String password) throws PasswordTooLongException {
if (password == null) {
throw new IllegalArgumentException("Password can not be null");
}
if (password.length() > Account.MAX_PASSWORD_LENGTH_SIZE) {
throw new PasswordTooLongException();
}
final Account user = Utils.getUser(true);
user.setPassword(password);
userService.changePassword(user);
}
@RequestMapping(method = RequestMethod.GET, value = "", produces = {"application/json"})
public RestUser fetchAccount() {
final Account user = Utils.getUser(true);
return new RestUser(user);
}
@RequestMapping(method = RequestMethod.PUT, value = "/firstname", consumes = {"text/plain"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void changeFirstname(@RequestBody String firstname) {
if (firstname == null) {
throw new IllegalArgumentException("Firstname can not be null");
}
final Account user = Utils.getUser(true);
user.setFirstname(firstname);
userService.updateUser(user);
}
@RequestMapping(method = RequestMethod.PUT, value = "/lastname", consumes = {"text/plain"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void changeLastName(@RequestBody String lastname) {
if (lastname == null) {
throw new IllegalArgumentException("lastname can not be null");
}
final Account user = Utils.getUser(true);
user.setLastname(lastname);
userService.updateUser(user);
}
@RequestMapping(method = RequestMethod.PUT, value = "/locale", consumes = {"text/plain"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void changeLanguage(@RequestBody String language) {
if (language == null) {
throw new IllegalArgumentException("language can not be null");
}
final Account user = Utils.getUser(true);
user.setLocale(language);
userService.updateUser(user);
}
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@RequestMapping(method = RequestMethod.DELETE, value = "")
public void deleteUser() throws WiseMappingException {
// Delete collaborations ...
final Account user = Utils.getUser(true);
final List<Collaboration> collaborations = mindmapService.findCollaborations(user);
for (Collaboration collaboration : collaborations) {
final Mindmap mindmap = collaboration.getMindMap();
mindmapService.removeMindmap(mindmap, user);
}
// Delete labels ....
final List<MindmapLabel> labels = labelService.getAll(user);
labels.forEach(l -> {
try {
labelService.removeLabel(l, user);
} catch (WiseMappingException e) {
throw new IllegalStateException(e);
}
});
// Finally, delete user ...
userService.removeUser(user);
}
}

View File

@@ -1,20 +1,20 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest;
@@ -22,25 +22,22 @@ import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.AuthenticationType;
import com.wisemapping.model.Collaboration;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import com.wisemapping.rest.model.RestUser;
import com.wisemapping.service.MindmapService;
import com.wisemapping.service.UserService;
import org.jetbrains.annotations.NotNull;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.List;
import java.util.regex.Pattern;
@Controller
@RestController
@RequestMapping("/api/restful/admin")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_ADMIN')")
public class AdminController extends BaseController {
@Qualifier("userService")
@Autowired
@@ -50,29 +47,29 @@ public class AdminController extends BaseController {
@Autowired
private MindmapService mindmapService;
@RequestMapping(method = RequestMethod.GET, value = "admin/users/{id}", produces = {"application/json", "application/xml"})
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}", produces = {"application/json"})
@ResponseBody
public RestUser getUserById(@PathVariable int id) throws IOException {
final User userBy = userService.getUserBy(id);
public RestUser getUserById(@PathVariable int id) {
final Account userBy = userService.getUserBy(id);
if (userBy == null) {
throw new IllegalArgumentException("User could not be found");
}
return new RestUser(userBy);
}
@RequestMapping(method = RequestMethod.GET, value = "admin/users/email/{email:.+}", produces = {"application/json", "application/xml"})
@RequestMapping(method = RequestMethod.GET, value = "/users/email/{email:.+}", produces = {"application/json"})
@ResponseBody
public RestUser getUserByEmail(@PathVariable String email) throws IOException {
final User user = userService.getUserBy(email);
public RestUser getUserByEmail(@PathVariable String email) {
final Account user = userService.getUserBy(email);
if (user == null) {
throw new IllegalArgumentException("User '" + email + "' could not be found");
}
return new RestUser(user);
}
@RequestMapping(method = RequestMethod.POST, value = "admin/users", consumes = {"application/xml", "application/json"}, produces = {"application/json", "application/xml"})
@RequestMapping(method = RequestMethod.POST, value = "/users", consumes = {"application/json"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.CREATED)
public void createUser(@RequestBody RestUser user, HttpServletResponse response) throws WiseMappingException {
public void createUser(@RequestBody RestUser user, final HttpServletResponse response) throws WiseMappingException {
if (user == null) {
throw new IllegalArgumentException("User could not be found");
}
@@ -84,7 +81,7 @@ public class AdminController extends BaseController {
}
// Run some other validations ...
final User delegated = user.getDelegated();
final Account delegated = user.getDelegated();
final String lastname = delegated.getLastname();
if (lastname == null || lastname.isEmpty()) {
throw new IllegalArgumentException("lastname can not be null");
@@ -104,17 +101,17 @@ public class AdminController extends BaseController {
// Finally create the user ...
delegated.setAuthenticationType(AuthenticationType.DATABASE);
userService.createUser(delegated, false, true);
response.setHeader("Location", "/service/admin/users/" + user.getId());
response.setHeader("Location", "/api/restful/admin/users/" + user.getId());
}
@RequestMapping(method = RequestMethod.PUT, value = "admin/users/{id}/password", consumes = {"text/plain"})
@RequestMapping(method = RequestMethod.PUT, value = "/users/{id}/password", consumes = {"text/plain"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void changePassword(@RequestBody String password, @PathVariable int id) throws WiseMappingException {
public void changePassword(@RequestBody String password, @PathVariable int id) {
if (password == null) {
throw new IllegalArgumentException("Password can not be null");
}
final User user = userService.getUserBy(id);
final Account user = userService.getUserBy(id);
if (user == null) {
throw new IllegalArgumentException("User '" + id + "' could not be found");
}
@@ -122,10 +119,10 @@ public class AdminController extends BaseController {
userService.changePassword(user);
}
@RequestMapping(method = RequestMethod.DELETE, value = "admin/users/{id}")
@RequestMapping(method = RequestMethod.DELETE, value = "/users/{id}")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void deleteUserByEmail(@PathVariable int id) throws WiseMappingException {
final User user = userService.getUserBy(id);
final Account user = userService.getUserBy(id);
if (user == null) {
throw new IllegalArgumentException("User '" + id + "' could not be found");
}
@@ -133,9 +130,8 @@ public class AdminController extends BaseController {
final List<Collaboration> collaborations = mindmapService.findCollaborations(user);
for (Collaboration collaboration : collaborations) {
final Mindmap mindmap = collaboration.getMindMap();
mindmapService.removeMindmap(mindmap,user);
mindmapService.removeMindmap(mindmap, user);
}
userService.removeUser(user);
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest;
import com.wisemapping.rest.model.RestAppConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/restful/app")
public class AppController extends BaseController {
@Value("${app.security.oauth2.google.url:}")
private String googleOauth2Url;
@Value("${app.registration.enabled:true}")
private Boolean isRegistrationEnabled;
@Value("${app.registration.captcha.enabled:false}")
private Boolean isCaptchaEnabled;
@Value("${app.registration.captcha.siteKey:}")
private String captchaSiteKey;
@Value("${app.site.api-base-url:}")
private String apiBaseUrl;
@Value("${app.site.ui-base-url:}")
private String uiBaseUrl;
@Value("${app.analytics.account:}")
private String analyticsAccount;
@Value("${app.jwt.expirationMin:10080}")
private int jwtExpirationMin;
@RequestMapping(method = RequestMethod.GET, value = "/config")
@ResponseStatus(value = HttpStatus.OK)
public RestAppConfig appConfig() {
return new RestAppConfig.RestAppConfigBuilder()
.setApiUrl(apiBaseUrl)
.setUiUrl(uiBaseUrl)
.setCaptchaSiteKey(captchaSiteKey)
.setGoogleOauth2Url(googleOauth2Url)
.setAnalyticsAccount(analyticsAccount)
.setRegistrationEnabled(isRegistrationEnabled)
.setJwtExpirationMin(jwtExpirationMin)
.build();
}
public String getGoogleOauth2Url() {
return googleOauth2Url;
}
public void setGoogleOauth2Url(String googleOauth2Url) {
this.googleOauth2Url = googleOauth2Url;
}
public Boolean getRegistrationEnabled() {
return isRegistrationEnabled;
}
public void setRegistrationEnabled(Boolean registrationEnabled) {
isRegistrationEnabled = registrationEnabled;
}
public Boolean getCaptchaEnabled() {
return isCaptchaEnabled;
}
public void setCaptchaEnabled(Boolean captchaEnabled) {
isCaptchaEnabled = captchaEnabled;
}
public String getCaptchaSiteKey() {
return captchaSiteKey;
}
public void setCaptchaSiteKey(String captchaSiteKey) {
this.captchaSiteKey = captchaSiteKey;
}
public String getApiBaseUrl() {
return apiBaseUrl;
}
public void setApiBaseUrl(String apiBaseUrl) {
this.apiBaseUrl = apiBaseUrl;
}
}

View File

@@ -17,66 +17,74 @@
*/
package com.wisemapping.rest;
import com.wisemapping.exceptions.ClientException;
import com.wisemapping.exceptions.Severity;
import com.wisemapping.mail.NotificationService;
import com.wisemapping.model.User;
import com.wisemapping.exceptions.*;
import com.wisemapping.model.Account;
import com.wisemapping.rest.model.RestErrors;
import com.wisemapping.security.Utils;
import com.wisemapping.service.NotificationService;
import com.wisemapping.service.RegistrationException;
import org.apache.log4j.Logger;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Locale;
public class BaseController {
final private Logger logger = Logger.getLogger(BaseController.class);
final private Logger logger = LogManager.getLogger();
@Qualifier("messageSource")
@Autowired
private ResourceBundleMessageSource messageSource;
@Autowired
ServletContext context;
@Autowired
private NotificationService notificationService;
private ServletContext context;
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public RestErrors handleClientErrors(@NotNull IllegalArgumentException ex) {
logger.error(ex.getMessage(), ex);
return new RestErrors(ex.getMessage(), Severity.WARNING);
}
@ExceptionHandler(AuthenticationCredentialsNotFoundException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public RestErrors handleAuthException(@NotNull final AuthenticationCredentialsNotFoundException ex) {
logger.debug(ex.getMessage(), ex);
return new RestErrors("Authentication exception. Session must be expired. Try logging again.", Severity.INFO);
}
@ExceptionHandler(ValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public RestErrors handleValidationErrors(@NotNull ValidationException ex) {
public RestErrors handleValidationErrors(@NotNull final ValidationException ex) {
logger.debug(ex.getMessage(), ex);
return new RestErrors(ex.getErrors(), messageSource);
}
@ExceptionHandler(JsonHttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public RestErrors handleJSONErrors(@NotNull JsonHttpMessageNotReadableException ex) {
logger.error(ex.getMessage(), ex);
return new RestErrors("Communication error", Severity.SEVERE);
}
@ExceptionHandler(java.lang.reflect.UndeclaredThrowableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public RestErrors handleSecurityErrors(@NotNull UndeclaredThrowableException ex) {
logger.error(ex.getMessage(), ex);
final Throwable cause = ex.getCause();
RestErrors result;
if (cause instanceof ClientException) {
@@ -94,21 +102,41 @@ public class BaseController {
return new RestErrors(ex.getMessage(messageSource, locale), ex.getSeverity(), ex.getTechInfo());
}
@ExceptionHandler(AccessDeniedSecurityException.class)
@ResponseBody
@ResponseStatus(HttpStatus.FORBIDDEN)
public RestErrors handleAccessDeniedSecurityException(@NotNull AccessDeniedSecurityException ex) {
return new RestErrors(ex.getMessage(), ex.getSeverity(), ex.getTechInfo());
}
@ExceptionHandler(OAuthAuthenticationException.class)
@ResponseBody
public OAuthAuthenticationException handleOAuthErrors(@NotNull OAuthAuthenticationException ex, HttpServletResponse response) {
// @todo: Further research needed for this error. No clear why this happens.
// Caused by: com.wisemapping.service.http.HttpInvokerException: error invoking https://oauth2.googleapis.com/token, response: {
// "error": "invalid_grant",
// "error_description": "Bad Request"
//}, status: 400
//
logger.error(ex.getMessage(), ex);
response.setStatus(response.getStatus());
return ex;
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public RestErrors handleServerErrors(@NotNull Exception ex, @NotNull HttpServletRequest request) {
final User user = Utils.getUser(false);
notificationService.reportJavaException(ex, user, request);
logger.error(ex);
logger.error(ex.getMessage(), ex);
final Account user = Utils.getUser(false);
return new RestErrors(ex.getMessage(), Severity.SEVERE);
}
@ExceptionHandler(RegistrationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public RestErrors handleRegistrationErrors(@NotNull RegistrationException exception) {
return new RestErrors(exception, messageSource);
public RestErrors handleRegistrationErrors(@NotNull RegistrationException ex) {
return new RestErrors(ex, messageSource);
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.rest.model.RestJwtUser;
import com.wisemapping.security.JwtTokenUtil;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/restful")
public class JwtAuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
public ResponseEntity<String> createAuthenticationToken(@RequestBody RestJwtUser user, @NotNull HttpServletResponse response) throws WiseMappingException {
// Is a valid user ?
authenticate(user.getEmail(), user.getPassword());
final String result = jwtTokenUtil.doLogin(response, user.getEmail());
return ResponseEntity.ok(result);
}
private void authenticate(@NotNull String username, @NotNull String password) throws WiseMappingException {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (DisabledException | BadCredentialsException e) {
throw new WiseMappingException(e.getMessage(), e);
}
}
}

View File

@@ -18,35 +18,37 @@
package com.wisemapping.rest;
import com.wisemapping.exceptions.LabelCouldNotFoundException;
import com.wisemapping.exceptions.ValidationException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.Label;
import com.wisemapping.model.User;
import com.wisemapping.model.MindmapLabel;
import com.wisemapping.model.Account;
import com.wisemapping.rest.model.RestLabel;
import com.wisemapping.rest.model.RestLabelList;
import com.wisemapping.security.Utils;
import com.wisemapping.service.LabelService;
import com.wisemapping.validator.LabelValidator;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@Controller
@RestController
@RequestMapping("/api/restful/labels")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
public class LabelController extends BaseController {
@Qualifier("labelService")
@Autowired
private LabelService labelService;
@RequestMapping(method = RequestMethod.POST, value = "/labels", consumes = {"application/json", "application/xml"})
@RequestMapping(method = RequestMethod.POST, value = "", consumes = {"application/json"})
@ResponseStatus(value = HttpStatus.CREATED)
public void createLabel(@RequestBody RestLabel restLabel, @NotNull HttpServletResponse response, @RequestParam(required = false) String title) throws WiseMappingException {
// Overwrite title if it was specified by parameter.
@@ -57,26 +59,26 @@ public class LabelController extends BaseController {
// Validate ...
validate(restLabel);
final Label label = createLabel(restLabel);
final MindmapLabel label = createLabel(restLabel);
// Return the new created label ...
response.setHeader("Location", "/service/labels/" + label.getId());
response.setHeader("Location", "/api/restful/labels/" + label.getId());
response.setHeader("ResourceId", Long.toString(label.getId()));
}
@RequestMapping(method = RequestMethod.GET, value = "/labels", produces = {"application/json", "application/xml"})
@RequestMapping(method = RequestMethod.GET, value = "/", produces = {"application/json"})
public RestLabelList retrieveList() {
final User user = Utils.getUser();
final Account user = Utils.getUser();
assert user != null;
final List<Label> all = labelService.getAll(user);
final List<MindmapLabel> all = labelService.getAll(user);
return new RestLabelList(all);
}
@RequestMapping(method = RequestMethod.DELETE, value = "/labels/{id}")
@RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void deleteLabelById(@PathVariable int id) throws WiseMappingException {
final User user = Utils.getUser();
final Label label = labelService.findLabelById(id, user);
final Account user = Utils.getUser();
final MindmapLabel label = labelService.findLabelById(id, user);
if (label == null) {
throw new LabelCouldNotFoundException("Label could not be found. Id: " + id);
}
@@ -84,10 +86,10 @@ public class LabelController extends BaseController {
labelService.removeLabel(label, user);
}
@NotNull private Label createLabel(@NotNull final RestLabel restLabel) throws WiseMappingException {
final Label label = restLabel.getDelegated();
@NotNull private MindmapLabel createLabel(@NotNull final RestLabel restLabel) throws WiseMappingException {
final MindmapLabel label = restLabel.getDelegated();
// Add new label ...
final User user = Utils.getUser();
final Account user = Utils.getUser();
assert user != null;
labelService.addLabel(label, user);
return label;

View File

@@ -24,29 +24,32 @@ import com.wisemapping.rest.model.*;
import com.wisemapping.security.Utils;
import com.wisemapping.service.*;
import com.wisemapping.validator.MapInfoValidator;
import com.wisemapping.view.MindMapBean;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.validator.routines.EmailValidator;
import org.apache.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Controller
@RestController
@RequestMapping("/api/restful/maps")
public class MindmapController extends BaseController {
final Logger logger = Logger.getLogger(MindmapController.class);
private final Logger logger = LogManager.getLogger();
private static final String LATEST_HISTORY_REVISION = "latest";
@@ -58,29 +61,60 @@ public class MindmapController extends BaseController {
@Autowired
private LabelService labelService;
@RequestMapping(method = RequestMethod.GET, value = "/maps/{id}", produces = {"application/json", "application/xml", "text/html"})
@Qualifier("userService")
@Autowired
private UserService userService;
@Value("${app.accounts.max-inactive:20}")
private int maxAccountsInactive;
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/{id}", produces = {"application/json"})
@ResponseBody
public RestMindmap retrieve(@PathVariable int id) throws WiseMappingException {
final User user = Utils.getUser();
final Account user = Utils.getUser(true);
final Mindmap mindMap = findMindmapById(id);
return new RestMindmap(mindMap, user);
}
@RequestMapping(method = RequestMethod.GET, value = "/maps/", produces = {"application/json", "application/xml"})
public RestMindmapList retrieveList(@RequestParam(required = false) String q) throws IOException {
final User user = Utils.getUser();
@PreAuthorize("permitAll()")
@RequestMapping(method = RequestMethod.GET, value = "/{id}/metadata", produces = {"application/json"})
@ResponseBody
public RestMindmapMetadata retrieveMetadata(@PathVariable int id) throws WiseMappingException {
final Account user = Utils.getUser(false);
final Mindmap mindmap = findMindmapById(id);
final MindMapBean mindMapBean = new MindMapBean(mindmap, user);
// Is the mindmap locked ?.
boolean isLocked = false;
final LockManager lockManager = this.mindmapService.getLockManager();
String lockFullName = null;
if (lockManager.isLocked(mindmap) && !lockManager.isLockedBy(mindmap, user)) {
final LockInfo lockInfo = lockManager.getLockInfo(mindmap);
isLocked = true;
lockFullName = lockInfo.getUser().getFullName();
}
return new RestMindmapMetadata(mindmap.getTitle(), mindMapBean.getProperties(), mindmap.getCreator().getFullName(), isLocked, lockFullName);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/", produces = {"application/json"})
public RestMindmapList retrieveList(@RequestParam(required = false) String q) {
final Account user = Utils.getUser(true);
final MindmapFilter filter = MindmapFilter.parse(q);
List<Mindmap> mindmaps = mindmapService.findMindmapsByUser(user);
mindmaps = mindmaps
.stream()
.filter(m -> filter.accept(m, user))
.collect(Collectors.toUnmodifiableList());
.filter(m -> filter.accept(m, user)).toList();
return new RestMindmapList(mindmaps, user);
}
@RequestMapping(method = RequestMethod.GET, value = "/maps/{id}/history/", produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/{id}/history/", produces = {"application/json"})
public RestMindmapHistoryList fetchHistory(@PathVariable int id) {
final List<MindMapHistory> histories = mindmapService.findMindmapHistory(id);
final RestMindmapHistoryList result = new RestMindmapHistoryList();
@@ -90,31 +124,13 @@ public class MindmapController extends BaseController {
return result;
}
@RequestMapping(value = "/maps/{id}/history/{hid}", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updateRevertMindmap(@PathVariable int id, @PathVariable String hid) throws WiseMappingException, IOException {
final Mindmap mindmap = findMindmapById(id);
final User user = Utils.getUser();
if (LATEST_HISTORY_REVISION.equals(hid)) {
// Revert to the latest stored version ...
List<MindMapHistory> mindmapHistory = mindmapService.findMindmapHistory(id);
if (mindmapHistory.size() > 0) {
final MindMapHistory mindMapHistory = mindmapHistory.get(0);
mindmap.setZippedXml(mindMapHistory.getZippedXml());
saveMindmapDocument(true, mindmap, user);
}
} else {
mindmapService.revertChange(mindmap, Integer.parseInt(hid));
}
}
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/document", consumes = {"application/xml", "application/json"}, produces = {"application/json", "application/xml"})
@RequestMapping(method = RequestMethod.PUT, value = "/{id}/document", consumes = {"application/json"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
public void updateDocument(@RequestBody RestMindmap restMindmap, @PathVariable int id, @RequestParam(required = false) boolean minor) throws WiseMappingException, IOException {
final Mindmap mindmap = findMindmapById(id);
final User user = Utils.getUser();
final Account user = Utils.getUser(true);
// Validate arguments ...
final String properties = restMindmap.getProperties();
@@ -138,7 +154,28 @@ public class MindmapController extends BaseController {
saveMindmapDocument(minor, mindmap, user);
}
@RequestMapping(method = RequestMethod.GET, value = {"/maps/{id}/document/xml", "/maps/{id}/document/xml-pub"}, consumes = {"text/plain"}, produces = {"application/xml; charset=UTF-8"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(value = "/{id}/history/{hid}", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updateRevertMindmap(@PathVariable int id, @PathVariable String hid) throws WiseMappingException, IOException {
final Mindmap mindmap = findMindmapById(id);
final Account user = Utils.getUser(true);
if (LATEST_HISTORY_REVISION.equals(hid)) {
// Revert to the latest stored version ...
List<MindMapHistory> mindmapHistory = mindmapService.findMindmapHistory(id);
if (mindmapHistory.size() > 0) {
final MindMapHistory mindMapHistory = mindmapHistory.get(0);
mindmap.setZippedXml(mindMapHistory.getZippedXml());
saveMindmapDocument(true, mindmap, user);
}
} else {
mindmapService.revertChange(mindmap, Integer.parseInt(hid));
}
}
@PreAuthorize("permitAll()")
@RequestMapping(method = RequestMethod.GET, value = {"/{id}/document/xml", "/{id}/document/xml-pub"}, consumes = {"text/plain"}, produces = {"application/xml; charset=UTF-8"})
@ResponseBody
public byte[] retrieveDocument(@PathVariable int id, @NotNull HttpServletResponse response) throws WiseMappingException, IOException {
final Mindmap mindmap = findMindmapById(id);
@@ -147,34 +184,36 @@ public class MindmapController extends BaseController {
return xmlStr.getBytes(StandardCharsets.UTF_8);
}
@RequestMapping(method = RequestMethod.PUT, value = {"/maps/{id}/document/xml"}, consumes = {"text/plain"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = {"/{id}/document/xml"}, consumes = {"text/plain"})
@ResponseBody
public void updateDocument(@PathVariable int id, @RequestBody String xmlDoc) throws WiseMappingException, IOException {
public void updateDocument(@PathVariable int id, @RequestBody String xmlDoc) throws WiseMappingException {
final Mindmap mindmap = findMindmapById(id);
final User user = Utils.getUser();
final Account user = Utils.getUser(true);
mindmap.setXmlStr(xmlDoc);
saveMindmapDocument(false, mindmap, user);
}
@RequestMapping(method = RequestMethod.GET, value = {"/maps/{id}/{hid}/document/xml"}, consumes = {"text/plain"}, produces = {"application/xml; charset=UTF-8"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = {"/{id}/{hid}/document/xml"}, consumes = {"text/plain"}, produces = {"application/xml; charset=UTF-8"})
@ResponseBody
public byte[] retrieveDocument(@PathVariable int id, @PathVariable int hid, @NotNull HttpServletResponse response) throws WiseMappingException, IOException {
final MindMapHistory mindmapHistory = mindmapService.findMindmapHistory(id, hid);
return mindmapHistory.getUnzipXml();
}
/**
* The intention of this method is the update of several properties at once ...
*/
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}", consumes = {"application/xml", "application/json"}, produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/{id}", consumes = {"application/json"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updateProperties(@RequestBody RestMindmap restMindmap, @PathVariable int id, @RequestParam(required = false) boolean minor) throws IOException, WiseMappingException {
final Mindmap mindmap = findMindmapById(id);
final User user = Utils.getUser();
final Account user = Utils.getUser(true);
final String xml = restMindmap.getXml();
if (xml != null && !xml.isEmpty()) {
@@ -185,7 +224,7 @@ public class MindmapController extends BaseController {
final String title = restMindmap.getTitle();
if (title != null && !title.equals(mindmap.getTitle())) {
if (mindmapService.getMindmapByTitle(title, user) != null) {
throw buildValidationException("title", "You already have a map with this title");
throw buildValidationException("You already have a map with this title");
}
mindmap.setTitle(title);
}
@@ -210,7 +249,7 @@ public class MindmapController extends BaseController {
@NotNull
private Mindmap findMindmapById(int id) throws MapCouldNotFoundException, AccessDeniedSecurityException {
// Has enough permissions ?
final User user = Utils.getUser();
final Account user = Utils.getUser();
if (!mindmapService.hasPermissions(user, id, CollaborationRole.VIEWER)) {
throw new AccessDeniedSecurityException(id, user);
}
@@ -223,16 +262,17 @@ public class MindmapController extends BaseController {
return result;
}
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/title", consumes = {"text/plain"}, produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/{id}/title", consumes = {"text/plain"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updateTitle(@RequestBody String title, @PathVariable int id) throws WiseMappingException {
final Mindmap mindMap = findMindmapById(id);
final User user = Utils.getUser();
final Account user = Utils.getUser(true);
// Is there a map with the same name ?
if (mindmapService.getMindmapByTitle(title, user) != null) {
throw buildValidationException("title", "You already have a mindmap with this title");
throw buildValidationException("You already have a mindmap with this title");
}
// Update map ...
@@ -241,17 +281,21 @@ public class MindmapController extends BaseController {
mindmapService.updateMindmap(mindMap, false);
}
@RequestMapping(method = RequestMethod.POST, value = "/maps/{id}/collabs/", consumes = {"application/json", "application/xml"}, produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/{id}/collabs/", consumes = {"application/json"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updateCollabs(@PathVariable int id, @NotNull @RequestBody RestCollaborationList restCollabs) throws CollaborationException, MapCouldNotFoundException, AccessDeniedSecurityException, InvalidEmailException {
public void updateCollabs(@PathVariable int id, @NotNull @RequestBody RestCollaborationList restCollabs) throws CollaborationException, MapCouldNotFoundException, AccessDeniedSecurityException, InvalidEmailException, TooManyInactiveAccountsExceptions {
final Mindmap mindMap = findMindmapById(id);
// Only owner can change collaborators...
final User user = Utils.getUser();
final Account user = Utils.getUser();
if (!mindMap.hasPermissions(user, CollaborationRole.OWNER)) {
throw new IllegalArgumentException("No enough permissions");
}
// Do not allow more than 20 collabs not active
verifyActiveCollabs(restCollabs, user);
// Compare one by one if some of the elements has been changed ....
final Set<Collaboration> collabsToRemove = new HashSet<>(mindMap.getCollaborations());
for (RestCollaboration restCollab : restCollabs.getCollaborations()) {
@@ -279,7 +323,6 @@ public class MindmapController extends BaseController {
if (role != CollaborationRole.OWNER) {
mindmapService.addCollaboration(mindMap, restCollab.getEmail(), role, restCollabs.getMessage());
}
}
// Remove all collaborations that no applies anymore ..
@@ -288,17 +331,21 @@ public class MindmapController extends BaseController {
}
}
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/collabs/", consumes = {"application/json", "application/xml"}, produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/{id}/collabs/", consumes = {"application/json"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void addCollab(@PathVariable int id, @NotNull @RequestBody RestCollaborationList restCollabs) throws CollaborationException, MapCouldNotFoundException, AccessDeniedSecurityException, InvalidEmailException {
public void addCollab(@PathVariable int id, @NotNull @RequestBody RestCollaborationList restCollabs) throws CollaborationException, MapCouldNotFoundException, AccessDeniedSecurityException, InvalidEmailException, TooManyInactiveAccountsExceptions, OwnerCannotChangeException {
final Mindmap mindMap = findMindmapById(id);
// Only owner can change collaborators...
final User user = Utils.getUser();
final Account user = Utils.getUser();
if (!mindMap.hasPermissions(user, CollaborationRole.OWNER)) {
throw new AccessDeniedSecurityException("User must be owner to share mindmap");
}
// Do not allow more than 20 collabs not active
verifyActiveCollabs(restCollabs, user);
// Is valid email address ?
final EmailValidator emailValidator = EmailValidator.getInstance();
final Set<String> invalidEmails = restCollabs
@@ -312,46 +359,48 @@ public class MindmapController extends BaseController {
}
// Has any role changed ?. Just removed it.
final Map<String, Collaboration> mapsByEmail = mindMap
final Map<String, Collaboration> collabByEmail = mindMap
.getCollaborations()
.stream()
.collect(Collectors.toMap(collaboration -> collaboration.getCollaborator().getEmail(), collaboration -> collaboration));
restCollabs
.getCollaborations()
.forEach(collab -> {
final String email = collab.getEmail();
if (mapsByEmail.containsKey(email)) {
try {
mindmapService.removeCollaboration(mindMap, mapsByEmail.get(email));
} catch (CollaborationException e) {
logger.error(e);
}
}
});
// Great, let's add all the collabs again ...
for (RestCollaboration restCollab : restCollabs.getCollaborations()) {
final Collaboration collaboration = mindMap.findCollaboration(restCollab.getEmail());
// Validate role format ...
String roleStr = restCollab.getRole();
// Validate newRole format ...
final String roleStr = restCollab.getRole();
if (roleStr == null) {
throw new IllegalArgumentException(roleStr + " is not a valid role");
throw new IllegalArgumentException(roleStr + " is not a valid newRole");
}
// Is owner ?
final CollaborationRole role = CollaborationRole.valueOf(roleStr.toUpperCase());
if (role == CollaborationRole.OWNER) {
throw new IllegalArgumentException("Owner can not be added as part of the collaboration list.");
}
// Had the newRole changed ?. Otherwise, don't touch it.
final CollaborationRole newRole = CollaborationRole.valueOf(roleStr.toUpperCase());
final String collabEmail = restCollab.getEmail();
final Collaboration currentCollab = collabByEmail.get(collabEmail);
if (currentCollab == null || currentCollab.getRole() != newRole) {
mindmapService.addCollaboration(mindMap, restCollab.getEmail(), role, restCollabs.getMessage());
// Are we trying to change the owner ...
if (currentCollab != null && currentCollab.getRole() == CollaborationRole.OWNER) {
throw new OwnerCannotChangeException(collabEmail);
}
// Role can not be changed ...
if (newRole == CollaborationRole.OWNER) {
throw new OwnerCannotChangeException(collabEmail);
}
// This is collaboration that with different newRole, try to change it ...
if (currentCollab != null) {
mindmapService.removeCollaboration(mindMap, currentCollab);
}
mindmapService.addCollaboration(mindMap, collabEmail, newRole, restCollabs.getMessage());
}
}
}
@RequestMapping(method = RequestMethod.GET, value = "/maps/{id}/collabs", produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/{id}/collabs", produces = {"application/json"})
public RestCollaborationList retrieveList(@PathVariable int id) throws MapCouldNotFoundException, AccessDeniedSecurityException {
final Mindmap mindMap = findMindmapById(id);
@@ -367,7 +416,8 @@ public class MindmapController extends BaseController {
return result;
}
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/description", consumes = {"text/plain"}, produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/{id}/description", consumes = {"text/plain"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updateDescription(@RequestBody String description, @PathVariable int id) throws WiseMappingException {
final Mindmap mindmap = findMindmapById(id);
@@ -375,13 +425,14 @@ public class MindmapController extends BaseController {
mindmapService.updateMindmap(mindmap, false);
}
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/publish", consumes = {"text/plain"}, produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/{id}/publish", consumes = {"text/plain"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updatePublishState(@RequestBody String value, @PathVariable int id) throws WiseMappingException {
final Mindmap mindMap = findMindmapById(id);
final User user = Utils.getUser();
final Account user = Utils.getUser();
if (!mindMap.hasPermissions(user, CollaborationRole.OWNER)) {
throw new IllegalArgumentException("No enough to execute this operation");
}
@@ -392,17 +443,19 @@ public class MindmapController extends BaseController {
}
@RequestMapping(method = RequestMethod.DELETE, value = "/maps/{id}")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void deleteMapById(@PathVariable int id) throws IOException, WiseMappingException {
final User user = Utils.getUser();
public void deleteMapById(@PathVariable int id) throws WiseMappingException {
final Account user = Utils.getUser();
final Mindmap mindmap = findMindmapById(id);
mindmapService.removeMindmap(mindmap, user);
}
@RequestMapping(method = RequestMethod.DELETE, value = "/maps/{id}/collabs")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/{id}/collabs")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void deleteCollabByEmail(@PathVariable int id, @RequestParam(required = false) String email) throws IOException, WiseMappingException {
public void deleteCollabByEmail(@PathVariable int id, @RequestParam(required = false) String email) throws WiseMappingException {
logger.debug("Deleting permission for email:" + email);
// Is a valid email address ?
@@ -412,7 +465,7 @@ public class MindmapController extends BaseController {
}
final Mindmap mindmap = findMindmapById(id);
final User user = Utils.getUser();
final Account user = Utils.getUser();
// Only owner can change collaborators...
if (!mindmap.hasPermissions(user, CollaborationRole.OWNER)) {
@@ -431,38 +484,62 @@ public class MindmapController extends BaseController {
}
}
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/starred", consumes = {"text/plain"}, produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/{id}/starred", consumes = {"text/plain"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updateStarredState(@RequestBody String value, @PathVariable int id) throws WiseMappingException {
logger.debug("Update starred:" + value);
final Mindmap mindmap = findMindmapById(id);
final User user = Utils.getUser();
final Account user = Utils.getUser();
// Update map status ...
final boolean starred = Boolean.parseBoolean(value);
final Optional<Collaboration> collaboration = mindmap.findCollaboration(user);
if (!collaboration.isPresent()) {
if (collaboration.isEmpty()) {
throw new WiseMappingException("No enough permissions.");
}
collaboration.get().getCollaborationProperties().setStarred(starred);
mindmapService.updateCollaboration(user, collaboration.get());
}
@RequestMapping(method = RequestMethod.DELETE, value = "/maps/batch")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/{id}/starred", produces = {"text/plain"})
@ResponseBody
public String fetchStarred(@PathVariable int id) throws WiseMappingException {
final Mindmap mindmap = findMindmapById(id);
final Account user = Utils.getUser();
final Optional<Collaboration> collaboration = mindmap.findCollaboration(user);
if (collaboration.isEmpty()) {
throw new WiseMappingException("No enough permissions.");
}
boolean result = collaboration.get().getCollaborationProperties().getStarred();
return Boolean.toString(result);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/batch")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void batchDelete(@RequestParam() String ids) throws IOException, WiseMappingException {
final User user = Utils.getUser();
public void batchDelete(@RequestParam() String ids) throws WiseMappingException {
final Account user = Utils.getUser();
final String[] mapsIds = ids.split(",");
for (final String mapId : mapsIds) {
final Mindmap mindmap = findMindmapById(Integer.parseInt(mapId));
mindmapService.removeMindmap(mindmap, user);
try {
for (final String mapId : mapsIds) {
final Mindmap mindmap = findMindmapById(Integer.parseInt(mapId));
mindmapService.removeMindmap(mindmap, user);
}
} catch (Exception e) {
final AccessDeniedSecurityException accessDenied = new AccessDeniedSecurityException("Map could not be deleted. Maps to be deleted:" + ids);
accessDenied.initCause(e);
throw accessDenied;
}
}
@RequestMapping(method = RequestMethod.POST, value = "/maps", consumes = {"application/xml", "application/json"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "", consumes = {"application/xml", "application/json"})
@ResponseStatus(value = HttpStatus.CREATED)
public void createMap(@RequestBody(required = false) String mapXml, @NotNull HttpServletResponse response, @RequestParam(required = false) String title, @RequestParam(required = false) String description) throws IOException, WiseMappingException {
public void createMap(@RequestBody(required = false) String mapXml, @NotNull HttpServletResponse response, @RequestParam(required = false) String title, @RequestParam(required = false) String description) throws WiseMappingException {
final Mindmap mindmap = new Mindmap();
if (title != null && !title.isEmpty()) {
@@ -471,8 +548,6 @@ public class MindmapController extends BaseController {
if (description != null && !description.isEmpty()) {
mindmap.setDescription(description);
} else {
mindmap.setDescription("description");
}
// Validate ...
@@ -489,17 +564,18 @@ public class MindmapController extends BaseController {
mindmap.setXmlStr(mapXml);
// Add new mindmap ...
final User user = Utils.getUser(true);
final Account user = Utils.getUser(true);
mindmapService.addMindmap(mindmap, user);
// Return the new created map ...
response.setHeader("Location", "/service/maps/" + mindmap.getId());
response.setHeader("Location", "/api/restful/maps/" + mindmap.getId());
response.setHeader("ResourceId", Integer.toString(mindmap.getId()));
}
@RequestMapping(method = RequestMethod.POST, value = "/maps/{id}", consumes = {"application/xml", "application/json"}, produces = {"application/xml", "application/json", "text/plain"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/{id}", consumes = {"application/json"}, produces = {"application/json", "text/plain"})
@ResponseStatus(value = HttpStatus.CREATED)
public void createDuplicate(@RequestBody RestMindmapInfo restMindmap, @PathVariable int id, @NotNull HttpServletResponse response) throws IOException, WiseMappingException {
public void createDuplicate(@RequestBody RestMindmapInfo restMindmap, @PathVariable int id, @NotNull HttpServletResponse response) throws WiseMappingException {
// Validate ...
final BindingResult result = new BeanPropertyBindingResult(restMindmap, "");
new MapInfoValidator(mindmapService).validate(restMindmap.getDelegated(), result);
@@ -508,7 +584,7 @@ public class MindmapController extends BaseController {
}
// Some basic validations ...
final User user = Utils.getUser();
final Account user = Utils.getUser();
// Create a shallowCopy of the map ...
final Mindmap mindMap = findMindmapById(id);
@@ -520,29 +596,18 @@ public class MindmapController extends BaseController {
mindmapService.addMindmap(clonedMap, user);
// Return the new created map ...
response.setHeader("Location", "/service/maps/" + clonedMap.getId());
response.setHeader("Location", "/api/restful/maps/" + clonedMap.getId());
response.setHeader("ResourceId", Integer.toString(clonedMap.getId()));
}
private void saveMindmapDocument(boolean minor, @NotNull final Mindmap mindMap, @NotNull final User user) throws WiseMappingException {
final Calendar now = Calendar.getInstance();
mindMap.setLastModificationTime(now);
mindMap.setLastEditor(user);
mindmapService.updateMindmap(mindMap, !minor);
}
private ValidationException buildValidationException(@NotNull String fieldName, @NotNull String message) throws WiseMappingException {
final BindingResult result = new BeanPropertyBindingResult(new RestMindmap(), "");
result.rejectValue(fieldName, "error.not-specified", null, message);
return new ValidationException(result);
}
@RequestMapping(method = RequestMethod.DELETE, value = "/maps/{id}/labels/{lid}")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/{id}/labels/{lid}")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void removeLabelFromMap(@PathVariable int id, @PathVariable int lid) throws WiseMappingException {
final User user = Utils.getUser();
final Account user = Utils.getUser();
final Mindmap mindmap = findMindmapById(id);
final Label label = labelService.findLabelById(lid, user);
final MindmapLabel label = labelService.findLabelById(lid, user);
if (label == null) {
throw new LabelCouldNotFoundException("Label could not be found. Id: " + lid);
@@ -552,11 +617,12 @@ public class MindmapController extends BaseController {
mindmapService.updateMindmap(mindmap, false);
}
@RequestMapping(method = RequestMethod.POST, value = "/maps/{id}/labels", consumes = {"application/xml", "application/json"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/{id}/labels", consumes = {"application/json"})
@ResponseStatus(value = HttpStatus.OK)
public void updateLabel(@PathVariable int id, @RequestBody int lid) throws WiseMappingException {
final User user = Utils.getUser();
final Label label = labelService.findLabelById(lid, user);
final Account user = Utils.getUser();
final MindmapLabel label = labelService.findLabelById(lid, user);
if (label == null) {
throw new LabelCouldNotFoundException("Label could not be found. Id: " + lid);
}
@@ -566,9 +632,10 @@ public class MindmapController extends BaseController {
mindmapService.updateMindmap(mindmap, false);
}
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/lock", consumes = {"text/plain"}, produces = {"application/json", "application/xml"})
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/{id}/lock", consumes = {"text/plain"}, produces = {"application/json"})
public ResponseEntity<RestLockInfo> lockMindmap(@RequestBody String value, @PathVariable int id) throws WiseMappingException {
final User user = Utils.getUser();
final Account user = Utils.getUser();
final LockManager lockManager = mindmapService.getLockManager();
final Mindmap mindmap = findMindmapById(id);
@@ -582,4 +649,39 @@ public class MindmapController extends BaseController {
}
return result;
}
private void saveMindmapDocument(boolean minor, @NotNull final Mindmap mindMap, @NotNull final Account user) throws WiseMappingException {
final Calendar now = Calendar.getInstance();
mindMap.setLastModificationTime(now);
mindMap.setLastEditor(user);
mindmapService.updateMindmap(mindMap, !minor);
}
private ValidationException buildValidationException(@NotNull String message) throws WiseMappingException {
final BindingResult result = new BeanPropertyBindingResult(new RestMindmap(), "");
result.rejectValue("title", "error.not-specified", null, message);
return new ValidationException(result);
}
private void verifyActiveCollabs(@NotNull RestCollaborationList restCollabs, Account user) throws TooManyInactiveAccountsExceptions {
// Do not allow more than 20 new accounts per mindmap...
final List<Mindmap> userMindmaps = mindmapService.findMindmapsByUser(user);
final Set<String> allEmails = userMindmaps
.stream()
.filter(m -> m.hasPermissions(user, CollaborationRole.OWNER))
.map(Mindmap::getCollaborations)
.flatMap(Collection::stream)
.map(c -> c.getCollaborator().getEmail())
.collect(Collectors.toSet());
allEmails.addAll(restCollabs
.getCollaborations().stream()
.map(RestCollaboration::getEmail)
.collect(Collectors.toSet()));
long inactiveAccounts = allEmails.stream().filter(e -> userService.getUserBy(e) == null).count();
if (inactiveAccounts > maxAccountsInactive) {
throw new TooManyInactiveAccountsExceptions(inactiveAccounts);
}
}
}

View File

@@ -21,7 +21,7 @@
package com.wisemapping.rest;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,35 +29,35 @@ public abstract class MindmapFilter {
public static final MindmapFilter ALL = new MindmapFilter("all") {
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
boolean accept(@NotNull Mindmap mindmap, @NotNull Account user) {
return true;
}
};
public static final MindmapFilter MY_MAPS = new MindmapFilter("my_maps") {
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
boolean accept(@NotNull Mindmap mindmap, @NotNull Account user) {
return mindmap.getCreator().identityEquality(user);
}
};
public static final MindmapFilter STARRED = new MindmapFilter("starred") {
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
boolean accept(@NotNull Mindmap mindmap, @NotNull Account user) {
return mindmap.isStarred(user);
}
};
public static final MindmapFilter SHARED_WITH_ME = new MindmapFilter("shared_with_me") {
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
boolean accept(@NotNull Mindmap mindmap, @NotNull Account user) {
return !MY_MAPS.accept(mindmap, user);
}
};
public static final MindmapFilter PUBLIC = new MindmapFilter("public") {
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
boolean accept(@NotNull Mindmap mindmap, @NotNull Account user) {
return mindmap.isPublic();
}
};
@@ -88,7 +88,7 @@ public abstract class MindmapFilter {
return result;
}
abstract boolean accept(@NotNull Mindmap mindmap, @NotNull User user);
abstract boolean accept(@NotNull Mindmap mindmap, @NotNull Account user);
private static final class LabelFilter extends MindmapFilter {
@@ -97,7 +97,7 @@ public abstract class MindmapFilter {
}
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
boolean accept(@NotNull Mindmap mindmap, @NotNull Account user) {
return mindmap.hasLabel(this.id);
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.Account;
import com.wisemapping.rest.model.RestOath2CallbackResponse;
import com.wisemapping.security.JwtTokenUtil;
import com.wisemapping.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/restful/oauth2/")
@CrossOrigin
public class OAuth2Controller extends BaseController {
final private static Logger logger = LogManager.getLogger();
@Qualifier("userService")
@Autowired
private UserService userService;
@Qualifier("authenticationManager")
@Autowired
private AuthenticationManager authManager;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@RequestMapping(method = RequestMethod.POST, value = "googlecallback", produces = {"application/json"})
@ResponseStatus(value = HttpStatus.OK)
public RestOath2CallbackResponse processGoogleCallback(@NotNull @RequestParam String code, @NotNull HttpServletResponse response, @NotNull HttpServletRequest request) throws WiseMappingException {
logger.debug("ProcessGoogleCallback:" + code);
if (code == null) {
throw new WiseMappingException("Illegal argument exception: " + code);
}
final Account user = userService.createAndAuthUserFromGoogle(code);
String jwtToken = null;
if (user.getGoogleSync()) {
jwtToken = jwtTokenUtil.doLogin(response, user.getEmail());
}
// Response ...
return new RestOath2CallbackResponse(user, jwtToken);
}
@RequestMapping(method = RequestMethod.PUT, value = "confirmaccountsync", produces = {"application/json"})
@ResponseStatus(value = HttpStatus.OK)
public RestOath2CallbackResponse confirmAccountSync(@NotNull @RequestParam String email, @NotNull @RequestParam String code, @NotNull HttpServletResponse response) throws WiseMappingException {
logger.debug("ConfirmAccountSync:" + email + " - " + code);
if (code == null) {
throw new WiseMappingException("Illegal argument exception: " + email + " - " + code);
}
// Update login
final Account user = userService.confirmGoogleAccountSync(email, code);
// Add header ...
final String jwtToken = jwtTokenUtil.doLogin(response, email);
// Response ...
return new RestOath2CallbackResponse(user, jwtToken);
}
}

View File

@@ -19,29 +19,36 @@
package com.wisemapping.rest;
import com.wisemapping.exceptions.EmailNotExistsException;
import com.wisemapping.exceptions.PasswordTooLongException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.AuthenticationType;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import com.wisemapping.rest.model.RestResetPasswordResponse;
import com.wisemapping.rest.model.RestUserRegistration;
import com.wisemapping.service.*;
import com.wisemapping.validator.Messages;
import com.wisemapping.validator.UserValidator;
import org.apache.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Controller
@CrossOrigin
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/api/restful/users")
public class UserController extends BaseController {
@Qualifier("userService")
@Autowired
private UserService userService;
@@ -49,16 +56,34 @@ public class UserController extends BaseController {
@Autowired
private RecaptchaService captchaService;
@Value("${google.recaptcha2.enabled}")
private Boolean recatchaEnabled;
@Qualifier("authenticationManager")
@Autowired
private AuthenticationManager authManager;
private static final Logger logger = Logger.getLogger(UserController.class);
@Value("${app.registration.enabled:true}")
private Boolean registrationEnabled;
@Value("${app.registration.captcha.enabled:true}")
private Boolean registrationCaptchaEnabled;
@Value("${app.accounts.exclusion.domain:''}")
private String domainBanExclusion;
private static final Logger logger = LogManager.getLogger();
private static final String REAL_IP_ADDRESS_HEADER = "X-Real-IP";
@RequestMapping(method = RequestMethod.POST, value = "/users", produces = {"application/json", "application/xml"})
@RequestMapping(method = RequestMethod.POST, value = "/", produces = {"application/json"})
@ResponseStatus(value = HttpStatus.CREATED)
public void registerUser(@RequestBody RestUserRegistration registration, @NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws WiseMappingException, BindException {
public void registerUser(@RequestBody RestUserRegistration registration, @NotNull HttpServletRequest request,
@NotNull HttpServletResponse response) throws WiseMappingException, BindException {
logger.debug("Register new user:" + registration.getEmail());
if (!registrationEnabled) {
throw new WiseMappingException("Registration is disabled. You can enable it using app.registration.enabled");
}
if (registration.getPassword().length() > Account.MAX_PASSWORD_LENGTH_SIZE) {
throw new PasswordTooLongException();
}
// If tomcat is behind a reverse proxy, ip needs to be found in other header.
String remoteIp = request.getHeader(REAL_IP_ADDRESS_HEADER);
@@ -66,10 +91,9 @@ public class UserController extends BaseController {
remoteIp = request.getRemoteAddr();
}
logger.debug("Remote address" + remoteIp);
verify(registration, remoteIp);
final User user = new User();
final Account user = new Account();
user.setEmail(registration.getEmail().trim());
user.setFirstname(registration.getFirstname());
user.setLastname(registration.getLastname());
@@ -77,20 +101,23 @@ public class UserController extends BaseController {
user.setAuthenticationType(AuthenticationType.DATABASE);
userService.createUser(user, false, true);
response.setHeader("Location", "/service/users/" + user.getId());
response.setHeader("Location", "/api/restful/users/" + user.getId());
response.setHeader("ResourceId", Integer.toString(user.getId()));
}
@RequestMapping(method = RequestMethod.PUT, value = "/users/resetPassword", produces = {"application/json", "application/xml"})
@RequestMapping(method = RequestMethod.PUT, value = "/resetPassword", produces = {"application/json"})
@ResponseStatus(value = HttpStatus.OK)
public void resetPassword(@RequestParam String email) throws InvalidAuthSchemaException, EmailNotExistsException {
public RestResetPasswordResponse resetPassword(@RequestParam String email) throws InvalidAuthSchemaException, EmailNotExistsException {
try {
userService.resetPassword(email);
return userService.resetPassword(email);
} catch (InvalidUserEmailException e) {
throw new EmailNotExistsException(e);
}
}
private void verify(@NotNull final RestUserRegistration registration, @NotNull String remoteAddress) throws BindException {
private void verify(@NotNull final RestUserRegistration registration, @NotNull String remoteAddress)
throws BindException {
final BindException errors = new RegistrationException(registration, "registration");
final UserValidator validator = new UserValidator();
@@ -98,7 +125,7 @@ public class UserController extends BaseController {
validator.validate(registration, errors);
// If captcha is enabled, generate it ...
if (recatchaEnabled) {
if (registrationCaptchaEnabled) {
final String recaptcha = registration.getRecaptcha();
if (recaptcha != null) {
final String reCaptchaResponse = captchaService.verifyRecaptcha(remoteAddress, recaptcha);
@@ -115,5 +142,14 @@ public class UserController extends BaseController {
if (errors.hasErrors()) {
throw errors;
}
// Is excluded ?.
final List<String> excludedDomains = Arrays.asList(domainBanExclusion.split(","));
final String emailDomain = registration.getEmail().split("@")[1];
if (excludedDomains.contains(emailDomain)) {
throw new IllegalArgumentException(
"Email is part of ban exclusion list due to abuse. Please, contact site admin if you think this is an error."
+ emailDomain);
}
}
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.jetbrains.annotations.NotNull;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class RestAppConfig {
private String apiBaseUrl;
private String uiBaseUrl;
private String googleOauth2Url;
private boolean registrationEnabled;
private boolean recaptcha2Enabled;
private String recaptcha2SiteKey;
private String analyticsAccount;
private int jwtExpirationMin = 10080;
RestAppConfig() {
}
public String getApiBaseUrl() {
return apiBaseUrl;
}
public void setApiBaseUrl(String apiBaseUrl) {
this.apiBaseUrl = apiBaseUrl;
}
public String getGoogleOauth2Url() {
return googleOauth2Url;
}
public void setGoogleOauth2Url(String googleOauth2Url) {
this.googleOauth2Url = googleOauth2Url;
}
public boolean isRegistrationEnabled() {
return registrationEnabled;
}
public void setRegistrationEnabled(boolean registrationEnabled) {
this.registrationEnabled = registrationEnabled;
}
public boolean isRecaptcha2Enabled() {
return recaptcha2Enabled;
}
public void setRecaptcha2Enabled(boolean recaptcha2Enabled) {
this.recaptcha2Enabled = recaptcha2Enabled;
}
public String getRecaptcha2SiteKey() {
return recaptcha2SiteKey;
}
public void setRecaptcha2SiteKey(String recaptcha2SiteKey) {
this.recaptcha2SiteKey = recaptcha2SiteKey;
}
public String getAnalyticsAccount() {
return analyticsAccount;
}
public void setAnalyticsAccount(String analyticsAccount) {
this.analyticsAccount = analyticsAccount;
}
public int getJwtExpirationMin() {
return jwtExpirationMin;
}
public void setJwtExpirationMin(int jwtExpirationMin) {
this.jwtExpirationMin = jwtExpirationMin;
}
public String getUiBaseUrl() {
return uiBaseUrl;
}
public void setUiBaseUrl(String uiBaseUrl) {
this.uiBaseUrl = uiBaseUrl;
}
public static class RestAppConfigBuilder {
private String apiBaseUrl;
private String uiBaseUrl;
private String googleOauth2Url;
private boolean registrationEnabled;
private boolean isCatchaEnabled = false;
private String captchaSiteKey;
private String analyticsAccount;
private int jwtExpirationMin;
public RestAppConfigBuilder setCaptchaSiteKey(@NotNull String captchaSiteKey) {
this.captchaSiteKey = captchaSiteKey;
this.isCatchaEnabled = true;
return this;
}
public RestAppConfigBuilder setApiUrl(@NotNull String url) {
this.apiBaseUrl = url;
return this;
}
public RestAppConfigBuilder setUiUrl(@NotNull String url) {
this.uiBaseUrl = url;
return this;
}
public RestAppConfigBuilder setJwtExpirationMin(@NotNull int value) {
this.jwtExpirationMin = value;
return this;
}
public RestAppConfigBuilder setGoogleOauth2Url(@NotNull String googleOauth2Url) {
this.googleOauth2Url = googleOauth2Url;
return this;
}
private void setGoogleAnalyticsAccount(@NotNull String analyticsAccount) {
this.analyticsAccount = analyticsAccount;
}
public RestAppConfigBuilder setRegistrationEnabled(@NotNull boolean registrationEnabled) {
this.registrationEnabled = registrationEnabled;
return this;
}
public RestAppConfigBuilder setAnalyticsAccount(@NotNull String analyticsAccount) {
this.analyticsAccount = analyticsAccount;
return this;
}
@NotNull
public RestAppConfig build() {
final RestAppConfig result = new RestAppConfig();
result.googleOauth2Url = googleOauth2Url;
result.recaptcha2SiteKey = captchaSiteKey;
result.recaptcha2Enabled = isCatchaEnabled;
result.uiBaseUrl = uiBaseUrl;
result.apiBaseUrl = apiBaseUrl;
result.registrationEnabled = registrationEnabled;
result.analyticsAccount = analyticsAccount;
return result;
}
}
}

View File

@@ -24,12 +24,6 @@ import com.wisemapping.model.Collaboration;
import com.wisemapping.model.CollaborationRole;
import org.jetbrains.annotations.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "collaboration")
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,

View File

@@ -22,15 +22,9 @@ package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import org.jetbrains.annotations.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.List;
@XmlRootElement(name = "collaborations")
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
@@ -52,7 +46,6 @@ public class RestCollaborationList {
}
@XmlElement(name = "collaborations")
public List<RestCollaboration> getCollaborations() {
return collaborations;
}

View File

@@ -24,13 +24,11 @@ import com.wisemapping.model.Collaborator;
import com.wisemapping.util.TimeUtils;
import org.jetbrains.annotations.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import java.util.Calendar;
@XmlRootElement(name = "collaborator")
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,

View File

@@ -30,13 +30,8 @@ import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.*;
@XmlRootElement(name = "errors")
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
@@ -49,13 +44,13 @@ public class RestErrors {
private Errors errors;
@JsonIgnore
private List<String> gErrors;
private List<String> globalError;
@JsonIgnore
MessageSource messageSource;
private MessageSource messageSource;
@JsonIgnore
Severity gSeverity;
private Severity globalSeverity;
@Nullable
@JsonIgnore
@@ -69,8 +64,8 @@ public class RestErrors {
this.errors = errors;
this.messageSource = messageSource;
this.gErrors = this.processGlobalErrors(errors);
this.gSeverity = Severity.WARNING;
this.globalError = this.processGlobalErrors(errors);
this.globalSeverity = Severity.WARNING;
}
public RestErrors(@NotNull String errorMsg, @NotNull Severity severity) {
@@ -80,9 +75,9 @@ public class RestErrors {
public RestErrors(@NotNull String errorMsg, @NotNull Severity severity, @Nullable String debugInfo) {
this._debugInfo = debugInfo;
this.gErrors = new ArrayList<>();
this.gErrors.add(errorMsg);
this.gSeverity = severity;
this.globalError = new ArrayList<>();
this.globalError.add(errorMsg);
this.globalSeverity = severity;
}
private List<String> processGlobalErrors(@NotNull Errors errors) {
@@ -125,7 +120,7 @@ public class RestErrors {
@Nullable
public String getGlobalSeverity() {
return this.gSeverity.toString();
return this.globalSeverity.toString();
}
@Nullable
@@ -134,7 +129,17 @@ public class RestErrors {
}
public List<String> getGlobalErrors() {
return gErrors;
return globalError;
}
@Override
public String toString() {
return "RestErrors{" +
"errors=" + errors +
", gErrors=" + globalError +
", messageSource=" + messageSource +
", gSeverity=" + globalSeverity +
", _debugInfo='" + _debugInfo + '\'' +
'}';
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.jetbrains.annotations.NotNull;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class RestJwtUser {
private String email;
private String password;
public RestJwtUser(@NotNull String email, @NotNull String password) {
this.setEmail(email);
this.setPassword(password);
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@@ -1,21 +1,33 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.wisemapping.model.Label;
import com.wisemapping.model.MindmapLabel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY;
@XmlRootElement(name = "label")
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonAutoDetect(
fieldVisibility = NONE,
setterVisibility = PUBLIC_ONLY,
@@ -26,22 +38,22 @@ import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_
public class RestLabel {
@JsonIgnore
private final Label label;
private final MindmapLabel label;
public RestLabel() {
this(new Label());
this(new MindmapLabel());
}
public RestLabel(@NotNull final Label label) {
public RestLabel(@NotNull final MindmapLabel label) {
this.label = label;
}
public void setParent(@NotNull final Label parent) {
public void setParent(final MindmapLabel parent) {
this.label.setParent(parent);
}
@Nullable
public Label getParent() {
public MindmapLabel getParent() {
return this.label.getParent();
}
@@ -62,24 +74,16 @@ public class RestLabel {
label.setTitle(title);
}
public void setColor(@NotNull final String color) {
public void setColor(final String color) {
label.setColor(color);
}
public void setIconName(@NotNull final String iconName) {
label.setIconName(iconName);
}
@Nullable public String getColor() {
return label.getColor();
}
@Nullable public String getIconName() {
return label.getIconName();
}
@JsonIgnore
public Label getDelegated() {
public MindmapLabel getDelegated() {
return label;
}
}

View File

@@ -1,18 +1,13 @@
package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.wisemapping.model.Label;
import com.wisemapping.model.MindmapLabel;
import org.jetbrains.annotations.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlElement;
import java.util.ArrayList;
import java.util.List;
@XmlRootElement(name = "labels")
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
@@ -25,9 +20,9 @@ public class RestLabelList {
this.restLabels = new ArrayList<>();
}
public RestLabelList(@NotNull final List<Label> labels) {
public RestLabelList(@NotNull final List<MindmapLabel> labels) {
this.restLabels = new ArrayList<>(labels.size());
for (Label label : labels) {
for (MindmapLabel label : labels) {
this.restLabels.add(new RestLabel(label));
}
}

View File

@@ -21,18 +21,11 @@ package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.wisemapping.model.Collaborator;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import com.wisemapping.service.LockInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "lock")
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
@@ -47,7 +40,7 @@ public class RestLockInfo {
}
public RestLockInfo(@Nullable LockInfo lockInfo, @NotNull User user) {
public RestLockInfo(@Nullable LockInfo lockInfo, @NotNull Account user) {
this.email = user.getEmail();
}

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