Merge branch 'feature/springboot2' into develop

main
Paulo Gustavo Veiga 2024-03-24 10:15:42 -07:00
commit c287d47c84
237 changed files with 4039 additions and 5060 deletions

View File

@ -1 +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 +0,0 @@
CREATE TABLE COLLABORATOR ( id INTEGER NOT NULL IDENTITY, email VARCHAR(255) NOT NULL UNIQUE, 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), google_sync BOOLEAN, sync_code VARCHAR(255), google_token VARCHAR(255), FOREIGN KEY (colaborator_id) REFERENCES COLLABORATOR (id) ); CREATE TABLE MINDMAP ( id INTEGER NOT NULL IDENTITY, title VARCHAR(255) NOT NULL, description VARCHAR(255), xml LONGVARBINARY NOT NULL, public BOOLEAN NOT NULL, creation_date DATETIME, edition_date DATETIME, creator_id INTEGER NOT NULL, 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 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 +0,0 @@
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 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,5 @@
RENAME TABLE USER TO ACCOUNT;
RENAME TABLE LABEL TO MINDMAP_LABEL;
ALTER TABLE COLLABORATION
RENAME COLUMN colaboration_id to collaboration_id

View File

@ -1 +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 +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 +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), google_sync BOOL, sync_code VARCHAR(255), google_token VARCHAR(255), 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, 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, UNIQUE KEY UC_ROLE (mindmap_id,colaborator_id), 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 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 +0,0 @@
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,4 +0,0 @@
CREATE DATABASE wisemapping;
CREATE USER wisemapping WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE wisemapping TO wisemapping;

View File

@ -1,10 +0,0 @@
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 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,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;

21
docker-compose.yml 100644
View File

@ -0,0 +1,21 @@
version: '3'
services:
wise-api:
container_name: 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"

159
pom.xml
View File

@ -1,159 +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.1.0-SNAPSHOT</com.wisemapping.version>
<superpom.dir>${project.basedir}/wise-webapps</superpom.dir>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</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.1.0-SNAPSHOT</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-compiler-plugin</artifactId>
<version>3.11.0</version>
</plugin>
<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>3.3.1</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>
<configuration>
<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>

View File

@ -0,0 +1,7 @@
FROM amazoncorretto:17.0.10
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} ${@}"]

232
wise-api/pom.xml 100644
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.3</version>
</parent>
<groupId>org.wisemapping</groupId>
<artifactId>wise-api</artifactId>
<version>5.1.0-SNAPSHOT</version>
<name>WiseMapping API</name>
<url>https://www.wisemapping.org</url>
<properties>
<com.wisemapping.version>5.1.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.3</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.5.4</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.1.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.1</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.11.0</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,27 @@
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)
// .sibling(MvcAppConfig.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,70 @@
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/*/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

@ -17,14 +17,13 @@
*/
package com.wisemapping.dao;
import com.wisemapping.model.Label;
import com.wisemapping.model.User;
import jakarta.annotation.Resource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.SelectionQuery;
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;
@ -32,60 +31,55 @@ import java.util.List;
@Repository("labelManager")
public class LabelManagerImpl
implements LabelManager {
@Resource
private SessionFactory sessionFactory;
@Autowired
private EntityManager entityManager;
@Override
public void addLabel(@NotNull final Label label) {
public void addLabel(@NotNull final MindmapLabel label) {
saveLabel(label);
}
@Override
public void saveLabel(@NotNull final Label label) {
getSession().persist(label);
}
private Session getSession() {
return sessionFactory.getCurrentSession();
public void saveLabel(@NotNull final MindmapLabel label) {
entityManager.persist(label);
}
@NotNull
@Override
public List<Label> getAllLabels(@NotNull final User user) {
final SelectionQuery<Label> query = getSession().createSelectionQuery("from com.wisemapping.model.Label wisemapping where creator=:creatorId", Label.class);
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.list();
return query.getResultList();
}
@Nullable
@Override
public Label getLabelById(int id, @NotNull final User user) {
final Session session = getSession();
final SelectionQuery<Label> query = session.createSelectionQuery("from com.wisemapping.model.Label wisemapping where id=:id and creator=:creator", Label.class);
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<Label> resultList = query.getResultList();
final List<MindmapLabel> resultList = query.getResultList();
return getFirst(resultList);
}
@Nullable
@Override
public Label getLabelByTitle(@NotNull String title, @NotNull final User user) {
final SelectionQuery<Label> query = getSession().createSelectionQuery("from com.wisemapping.model.Label wisemapping where title=:title and creator=:creator", Label.class);
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 getFirst(query.list());
return query.getResultList().stream().findFirst().orElse(null);
}
@Override
public void removeLabel(@NotNull Label label) {
getSession().remove(label);
public void removeLabel(@NotNull MindmapLabel label) {
entityManager.remove(label);
}
@Nullable
private Label getFirst(final List<Label> labels) {
Label result = null;
private MindmapLabel getFirst(final List<MindmapLabel> labels) {
MindmapLabel result = null;
if (labels != null && !labels.isEmpty()) {
result = labels.get(0);
}

View File

@ -22,7 +22,6 @@ 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 {
@ -34,11 +33,11 @@ public interface MindmapManager {
@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);
@ -56,5 +55,5 @@ public interface MindmapManager {
void updateCollaboration(@NotNull Collaboration collaboration);
List<Mindmap> findMindmapByUser(User user);
List<Mindmap> findMindmapByUser(Account user);
}

View File

@ -19,16 +19,15 @@
package com.wisemapping.dao;
import com.wisemapping.model.*;
import jakarta.annotation.Resource;
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.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.SelectionQuery;
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;
@ -37,13 +36,14 @@ import java.util.List;
@Repository("mindmapManager")
public class MindmapManagerImpl
implements MindmapManager {
@Resource
private SessionFactory sessionFactory;
@Autowired
private EntityManager entityManager;
@Override
public Collaborator findCollaborator(@NotNull final String email) {
final Collaborator collaborator;
final SelectionQuery<Collaborator> query = getSession().createSelectionQuery("from com.wisemapping.model.Collaborator collaborator where email=:email", Collaborator.class);
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();
@ -56,14 +56,9 @@ public class MindmapManagerImpl
return collaborator;
}
private Session getSession() {
return sessionFactory.getCurrentSession();
}
@Override
public List<MindMapHistory> getHistoryFrom(int mindmapId) {
final Session session = getSession();
final CriteriaBuilder cb = session.getCriteriaBuilder();
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final CriteriaQuery<MindMapHistory> cr = cb.createQuery(MindMapHistory.class);
final Root<MindMapHistory> root = cr.from(MindMapHistory.class);
@ -72,7 +67,7 @@ public class MindmapManagerImpl
.where(cb.equal(root.get("mindmapId"), mindmapId))
.orderBy(cb.desc(root.get("creationTime")));
return session.
return entityManager.
createQuery(select)
.setMaxResults(30)
.getResultList();
@ -80,21 +75,19 @@ public class MindmapManagerImpl
@Override
public MindMapHistory getHistory(int historyId) {
final Session session = getSession();
return session.find(MindMapHistory.class, historyId);
return entityManager.find(MindMapHistory.class, historyId);
}
@Override
public void updateCollaboration(@NotNull Collaboration collaboration) {
final Session session = getSession();
session.persist(collaboration);
entityManager.persist(collaboration);
}
@Override
public List<Mindmap> findMindmapByUser(@NotNull User user) {
public List<Mindmap> findMindmapByUser(@NotNull Account user) {
final SelectionQuery<Mindmap> query = getSession()
.createSelectionQuery("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);
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();
@ -102,69 +95,64 @@ public class MindmapManagerImpl
@Override
public List<Collaboration> findCollaboration(final int collaboratorId) {
final SelectionQuery<Collaboration> query = getSession().createSelectionQuery("from com.wisemapping.model.Collaboration c where c.collaborator.id=:collaboratorId", Collaboration.class);
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) {
final Session session = getSession();
assert collaborator != null : "ADD MINDMAP COLLABORATOR: Collaborator is required!";
session.persist(collaborator);
entityManager.persist(collaborator);
}
@Override
public void removeCollaboration(Collaboration collaboration) {
final Session session = getSession();
session.remove(collaboration);
entityManager.remove(collaboration);
}
@Override
public void removeCollaborator(@NotNull Collaborator collaborator) {
final Session session = getSession();
session.remove(collaborator);
entityManager.remove(collaborator);
}
@Override
@Nullable
public Mindmap getMindmapById(int id) {
final Session session = getSession();
return session.get(Mindmap.class, id);
return entityManager.find(Mindmap.class, id);
}
@Override
public Mindmap getMindmapByTitle(final String title, final User user) {
final Mindmap result;
final SelectionQuery<Mindmap> query = getSession().createSelectionQuery("from com.wisemapping.model.Mindmap wisemapping where title=:title and creator=:creator", Mindmap.class);
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);
} else {
result = null;
}
return result;
}
@Override
public void addMindmap(User user, Mindmap mindMap) {
public void addMindmap(Account user, Mindmap mindMap) {
saveMindmap(mindMap);
}
@Override
public void saveMindmap(Mindmap mindMap) {
assert mindMap != null : "Save Mindmap: Mindmap is required!";
getSession().persist(mindMap);
entityManager.persist(mindMap);
}
@Override
public void updateMindmap(@NotNull Mindmap mindMap, boolean saveHistory) {
assert mindMap != null : "Save Mindmap: Mindmap is required!";
getSession().merge(mindMap);
entityManager.merge(mindMap);
if (saveHistory) {
saveHistory(mindMap);
}
@ -173,20 +161,19 @@ public class MindmapManagerImpl
@Override
public void removeMindmap(@NotNull final Mindmap mindmap) {
// Delete history first ...
final Session session = getSession();
final CriteriaBuilder cb = session.getCriteriaBuilder();
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()));
session.createMutationQuery(deleteStatement).executeUpdate();
entityManager.createQuery(deleteStatement).executeUpdate();
// Remove collaborations ...
mindmap.removedCollaboration(mindmap.getCollaborations());
// Delete mindmap ....
getSession().remove(mindmap);
entityManager.remove(mindmap);
}
private void saveHistory(@NotNull final Mindmap mindMap) {
@ -196,6 +183,6 @@ public class MindmapManagerImpl
history.setCreationTime(Calendar.getInstance());
history.setEditor(mindMap.getLastEditor());
history.setMindmapId(mindMap.getId());
getSession().merge(history);
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

@ -21,11 +21,8 @@ package com.wisemapping.dao;
import com.wisemapping.model.*;
import com.wisemapping.security.DefaultPasswordEncoderFactories;
import com.wisemapping.security.LegacyPasswordEncoder;
import jakarta.annotation.Resource;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.SelectionQuery;
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;
@ -40,33 +37,30 @@ import java.util.concurrent.CopyOnWriteArraySet;
public class UserManagerImpl
implements UserManager {
@Autowired
private SessionFactory sessionFactory;
private EntityManager entityManager;
@Autowired
private PasswordEncoder passwordEncoder;
public UserManagerImpl() {
}
public void setEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
public List<User> getAllUsers() {
return getSession().createSelectionQuery("from com.wisemapping.model.User user", User.class).getResultList();
public List<Account> getAllUsers() {
return entityManager.createQuery("from com.wisemapping.model.Account user", Account.class).getResultList();
}
private Session getSession() {
return sessionFactory.getCurrentSession();
}
@Override
@Nullable
public User getUserBy(@NotNull final String email) {
User user = null;
public Account getUserBy(@NotNull final String email) {
Account user = null;
SelectionQuery<User> query = getSession().createSelectionQuery("from com.wisemapping.model.User colaborator where email=:email",User.class);
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.getResultList();
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);
@ -78,8 +72,8 @@ public class UserManagerImpl
@Override
public Collaborator getCollaboratorBy(final String email) {
final Collaborator result;
Session session = getSession();
final SelectionQuery<Collaborator> query = session.createSelectionQuery("from com.wisemapping.model.Collaborator colaborator where " +
final TypedQuery<Collaborator> query = entityManager.createQuery("from com.wisemapping.model.Collaborator colaborator where " +
"email=:email", Collaborator.class);
query.setParameter("email", email);
@ -95,36 +89,29 @@ public class UserManagerImpl
@Nullable
@Override
public User getUserBy(int id) {
User user = null;
try {
user = getSession().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";
if (!AuthenticationType.GOOGLE_OAUTH2.equals(user.getAuthenticationType())) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
} else {
user.setPassword("");
}
getSession().persist(user);
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 ...
final Session session = getSession();
collaborator.setEmail(collaborator.getEmail() + "_toRemove");
session.merge(collaborator);
session.flush();
entityManager.merge(collaborator);
entityManager.flush();
// Save all new...
this.createUser(user);
@ -136,21 +123,21 @@ public class UserManagerImpl
}
// Delete old user ...
session.remove(collaborator);
entityManager.remove(collaborator);
return user;
}
@Override
public void removeUser(@NotNull final User user) {
getSession().remove(user);
public void removeUser(@NotNull final Account user) {
entityManager.remove(user);
}
public void auditLogin(@NotNull AccessAuditory accessAuditory) {
assert accessAuditory != null : "accessAuditory is null";
getSession().persist(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 ?
@ -159,17 +146,17 @@ public class UserManagerImpl
user.setPassword(passwordEncoder.encode(user.getPassword()));
}
getSession().merge(user);
entityManager.merge(user);
}
public User getUserByActivationCode(long code) {
final User user;
public Account getUserByActivationCode(long code) {
final Account user;
final SelectionQuery<User> query = getSession().createSelectionQuery("from com.wisemapping.model.User user where " +
"activationCode=:activationCode", User.class);
final TypedQuery<Account> query = entityManager.createQuery("from com.wisemapping.model.User user where " +
"activationCode=:activationCode", Account.class);
query.setParameter("activationCode", code);
final List<User> users = query.getResultList();
final List<Account> users = query.getResultList();
if (users != null && !users.isEmpty()) {
assert users.size() == 1 : "More than one user with the same username!";

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

@ -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

@ -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,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,7 +20,7 @@ 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;
@ -51,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

@ -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

@ -22,13 +22,14 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Calendar;
@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 {
@ -63,7 +64,7 @@ public class User
@Column(name = "google_token")
private String googleToken;
public User() {
public Account() {
}
public String getFullName() {
@ -164,7 +165,7 @@ public class User
}
public Boolean getGoogleSync() {
return googleSync;
return googleSync != null && googleSync;
}
public void setGoogleSync(Boolean googleSync) {

View File

@ -42,7 +42,7 @@ 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)

View File

@ -1,32 +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.
*/
* 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}";
public static final String DEFAULT_JSON_PROPERTIES = "{\"zoom\":0.8}";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;

View File

@ -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,7 +22,6 @@ 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;
@ -31,6 +30,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import jakarta.persistence.*;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
@ -51,14 +51,14 @@ 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
@JoinColumn(name = "last_editor_id", nullable = false)
@NotFound(action = NotFoundAction.IGNORE)
private User lastEditor;
private Account lastEditor;
private String description;
@ -75,7 +75,7 @@ public class Mindmap implements Serializable {
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;
@ -152,15 +152,15 @@ public class Mindmap implements Serializable {
}
@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);
}
@ -183,7 +183,7 @@ public class Mindmap implements Serializable {
return result;
}
public boolean isCreator(@NotNull User user) {
public boolean isCreator(@NotNull Account user) {
return this.getCreator() != null && this.getCreator().identityEquality(user);
}
@ -205,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;
}
@ -263,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;
}
@ -310,13 +310,10 @@ public class Mindmap implements Serializable {
}
public static String getDefaultMindmapXml(@NotNull final String title) {
final StringBuilder result = new StringBuilder();
result.append("<map version=\"tango\" theme=\"prism\">");
result.append("<topic central=\"true\" text=\"");
result.append(escapeXmlAttribute(title));
result.append("\"/></map>");
return result.toString();
return "<map version=\"tango\" theme=\"prism\">" +
"<topic central=\"true\" text=\"" +
escapeXmlAttribute(title) +
"\"/></map>";
}
static private String escapeXmlAttribute(String attValue) {
@ -350,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;
}
@ -358,7 +355,7 @@ public class Mindmap implements Serializable {
return false;
}
public void removeLabel(@NotNull final Label label) {
public void removeLabel(@NotNull final MindmapLabel label) {
this.labels.remove(label);
}
}

View File

@ -27,10 +27,10 @@ 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;
@ -39,34 +39,32 @@ public class Label implements Serializable {
private String title;
@NotNull
private String color;
@Nullable
private String iconName;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "creator_id", nullable = true, unique = true)
@NotNull
private User creator;
private Account creator;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_label_id", nullable = true)
@Nullable
private Label parent;
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;
}
@ -75,7 +73,7 @@ public class Label implements Serializable {
return title;
}
public void setTitle(@NotNull String title) {
public void setTitle(String title) {
this.title = title;
}
@ -87,30 +85,22 @@ 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;
if (!(o instanceof MindmapLabel)) return false;
final Label label = (Label) o;
final MindmapLabel label = (MindmapLabel) o;
return id == label.id && creator.getId() == label.creator.getId()
&& Objects.equals(parent, label.parent);
}

View File

@ -21,9 +21,9 @@ package com.wisemapping.rest;
import com.wisemapping.exceptions.PasswordTooLongException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.Collaboration;
import com.wisemapping.model.Label;
import com.wisemapping.model.MindmapLabel;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import com.wisemapping.rest.model.RestUser;
import com.wisemapping.security.Utils;
import com.wisemapping.service.LabelService;
@ -33,15 +33,12 @@ 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.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
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.*;
import java.util.List;
@Controller
@RestController
@RequestMapping("/api/restful/account")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
public class AccountController extends BaseController {
@Qualifier("userService")
@ -56,53 +53,53 @@ public class AccountController extends BaseController {
@Autowired
private LabelService labelService;
@RequestMapping(method = RequestMethod.PUT, value = "account/password", consumes = {"text/plain"})
@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() > User.MAX_PASSWORD_LENGTH_SIZE) {
if (password.length() > Account.MAX_PASSWORD_LENGTH_SIZE) {
throw new PasswordTooLongException();
}
final User user = Utils.getUser(true);
final Account user = Utils.getUser(true);
user.setPassword(password);
userService.changePassword(user);
}
@RequestMapping(method = RequestMethod.GET, value = "/account", produces = {"application/json"})
@RequestMapping(method = RequestMethod.GET, value = "", produces = {"application/json"})
public RestUser fetchAccount() {
final User user = Utils.getUser(true);
final Account user = Utils.getUser(true);
return new RestUser(user);
}
@RequestMapping(method = RequestMethod.PUT, value = "account/firstname", consumes = {"text/plain"})
@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 User user = Utils.getUser(true);
final Account user = Utils.getUser(true);
user.setFirstname(firstname);
userService.updateUser(user);
}
@RequestMapping(method = RequestMethod.PUT, value = "account/lastname", consumes = {"text/plain"})
@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 User user = Utils.getUser(true);
final Account user = Utils.getUser(true);
user.setLastname(lastname);
userService.updateUser(user);
}
@RequestMapping(method = RequestMethod.PUT, value = "account/locale", consumes = {"text/plain"})
@RequestMapping(method = RequestMethod.PUT, value = "/locale", consumes = {"text/plain"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void changeLanguage(@RequestBody String language) {
if (language == null) {
@ -110,16 +107,16 @@ public class AccountController extends BaseController {
}
final User user = Utils.getUser(true);
final Account user = Utils.getUser(true);
user.setLocale(language);
userService.updateUser(user);
}
@RequestMapping(method = RequestMethod.DELETE, value = "account")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@RequestMapping(method = RequestMethod.DELETE, value = "")
public void deleteUser() throws WiseMappingException {
// Delete collaborations ...
final User user = Utils.getUser(true);
final Account user = Utils.getUser(true);
final List<Collaboration> collaborations = mindmapService.findCollaborations(user);
for (Collaboration collaboration : collaborations) {
final Mindmap mindmap = collaboration.getMindMap();
@ -127,7 +124,7 @@ public class AccountController extends BaseController {
}
// Delete labels ....
final List<Label> labels = labelService.getAll(user);
final List<MindmapLabel> labels = labelService.getAll(user);
labels.forEach(l -> {
try {
labelService.removeLabel(l, user);

View File

@ -22,23 +22,21 @@ 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 jakarta.servlet.http.HttpServletResponse;
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.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@Controller
@RestController
@RequestMapping("/api/restful/admin")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_ADMIN')")
public class AdminController extends BaseController {
@Qualifier("userService")
@ -49,29 +47,29 @@ public class AdminController extends BaseController {
@Autowired
private MindmapService mindmapService;
@RequestMapping(method = RequestMethod.GET, value = "admin/users/{id}", produces = {"application/json"})
@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"})
@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/json"}, produces = {"application/json"})
@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");
}
@ -83,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");
@ -103,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");
}
@ -121,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");
}
@ -134,7 +132,6 @@ public class AdminController extends BaseController {
final Mindmap mindmap = collaboration.getMindMap();
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,11 +17,8 @@
*/
package com.wisemapping.rest;
import com.wisemapping.exceptions.ClientException;
import com.wisemapping.exceptions.OAuthAuthenticationException;
import com.wisemapping.exceptions.Severity;
import com.wisemapping.exceptions.ValidationException;
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;
@ -54,7 +51,7 @@ public class BaseController {
private ResourceBundleMessageSource messageSource;
@Autowired
ServletContext context;
private ServletContext context;
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ -105,6 +102,14 @@ 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) {
@ -124,8 +129,7 @@ public class BaseController {
@ResponseBody
public RestErrors handleServerErrors(@NotNull Exception ex, @NotNull HttpServletRequest request) {
logger.error(ex.getMessage(), ex);
final User user = Utils.getUser(false);
// notificationService.reportJavaException(ex, user, request);
final Account user = Utils.getUser(false);
return new RestErrors(ex.getMessage(), Severity.SEVERE);
}

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

@ -20,27 +20,27 @@ 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.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
@Controller
@RestController
@RequestMapping("/api/restful/labels")
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
public class LabelController extends BaseController {
@ -48,8 +48,7 @@ public class LabelController extends BaseController {
@Autowired
private LabelService labelService;
@RequestMapping(method = RequestMethod.POST, value = "/labels", consumes = {"application/json"})
@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.
@ -60,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"})
@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);
}
@ -87,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,6 +24,8 @@ 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.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -34,23 +36,18 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
@Controller
@Transactional(propagation = Propagation.REQUIRED)
@RestController
@RequestMapping("/api/restful/maps")
public class MindmapController extends BaseController {
private final Logger logger = LogManager.getLogger();
@ -68,23 +65,44 @@ public class MindmapController extends BaseController {
@Autowired
private UserService userService;
@Value("${accounts.maxInactive:20}")
@Value("${app.accounts.max-inactive:20}")
private int maxAccountsInactive;
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/maps/{id}", produces = {"application/json"})
@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);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/maps/", produces = {"application/json"})
@RequestMapping(method = RequestMethod.GET, value = "/{id}/metadata", produces = {"application/json"})
@ResponseBody
public RestMindmapMetadata retrieveMetadata(@PathVariable int id) throws WiseMappingException {
final Account user = Utils.getUser(true);
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 User user = Utils.getUser();
final Account user = Utils.getUser(true);
final MindmapFilter filter = MindmapFilter.parse(q);
List<Mindmap> mindmaps = mindmapService.findMindmapsByUser(user);
@ -96,7 +114,7 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/maps/{id}/history/", produces = {"application/json"})
@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();
@ -106,13 +124,13 @@ public class MindmapController extends BaseController {
return result;
}
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/document", consumes = {"application/json"}, produces = {"application/json"})
@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();
@ -137,11 +155,11 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(value = "/maps/{id}/history/{hid}", method = RequestMethod.POST)
@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 User user = Utils.getUser();
final Account user = Utils.getUser(true);
if (LATEST_HISTORY_REVISION.equals(hid)) {
// Revert to the latest stored version ...
@ -157,7 +175,7 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("permitAll()")
@RequestMapping(method = RequestMethod.GET, value = {"/maps/{id}/document/xml", "/maps/{id}/document/xml-pub"}, consumes = {"text/plain"}, produces = {"application/xml; charset=UTF-8"})
@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);
@ -167,11 +185,11 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = {"/maps/{id}/document/xml"}, consumes = {"text/plain"})
@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);
@ -179,24 +197,23 @@ public class MindmapController extends BaseController {
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = {"/maps/{id}/{hid}/document/xml"}, consumes = {"text/plain"}, produces = {"application/xml; charset=UTF-8"})
@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 ...
*/
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}", consumes = {"application/json"}, produces = {"application/json"})
@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()) {
@ -207,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);
}
@ -232,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);
}
@ -246,16 +263,16 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/title", consumes = {"text/plain"}, produces = {"application/json"})
@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 ...
@ -265,13 +282,13 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/maps/{id}/collabs/", consumes = {"application/json"}, produces = {"application/json"})
@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, 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");
}
@ -315,13 +332,13 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/collabs/", consumes = {"application/json"}, produces = {"application/json"})
@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, 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");
}
@ -383,7 +400,7 @@ public class MindmapController extends BaseController {
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/maps/{id}/collabs", produces = {"application/json"})
@RequestMapping(method = RequestMethod.GET, value = "/{id}/collabs", produces = {"application/json"})
public RestCollaborationList retrieveList(@PathVariable int id) throws MapCouldNotFoundException, AccessDeniedSecurityException {
final Mindmap mindMap = findMindmapById(id);
@ -400,7 +417,7 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/description", consumes = {"text/plain"}, produces = {"application/json"})
@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);
@ -409,13 +426,13 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/publish", consumes = {"text/plain"}, produces = {"application/json"})
@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");
}
@ -427,18 +444,18 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/maps/{id}")
@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);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/maps/{id}/collabs")
@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 ?
@ -448,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)) {
@ -468,18 +485,18 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/starred", consumes = {"text/plain"}, produces = {"application/json"})
@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);
@ -487,14 +504,14 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/maps/{id}/starred", produces = {"text/plain"})
@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 User user = Utils.getUser();
final Account user = Utils.getUser();
final Optional<Collaboration> collaboration = mindmap.findCollaboration(user);
if (!collaboration.isPresent()) {
if (collaboration.isEmpty()) {
throw new WiseMappingException("No enough permissions.");
}
boolean result = collaboration.get().getCollaborationProperties().getStarred();
@ -502,10 +519,10 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/maps/batch")
@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(",");
try {
for (final String mapId : mapsIds) {
@ -520,9 +537,9 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/maps", consumes = {"application/xml", "application/json"})
@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()) {
@ -547,18 +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()));
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/maps/{id}", consumes = {"application/json"}, produces = {"application/json", "text/plain"})
@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);
@ -567,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);
@ -579,18 +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()));
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/maps/{id}/labels/{lid}")
@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);
@ -601,11 +618,11 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/maps/{id}/labels", consumes = {"application/json"})
@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);
}
@ -616,9 +633,9 @@ public class MindmapController extends BaseController {
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/lock", consumes = {"text/plain"}, produces = {"application/json"})
@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);
@ -634,20 +651,20 @@ public class MindmapController extends BaseController {
}
private void saveMindmapDocument(boolean minor, @NotNull final Mindmap mindMap, @NotNull final User user) throws WiseMappingException {
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 fieldName, @NotNull String message) throws WiseMappingException {
private ValidationException buildValidationException(@NotNull String message) throws WiseMappingException {
final BindingResult result = new BeanPropertyBindingResult(new RestMindmap(), "");
result.rejectValue(fieldName, "error.not-specified", null, message);
result.rejectValue("title", "error.not-specified", null, message);
return new ValidationException(result);
}
private void verifyActiveCollabs(@NotNull RestCollaborationList restCollabs, User user) throws TooManyInactiveAccountsExceptions {
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

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

@ -0,0 +1,155 @@
/*
* 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.EmailNotExistsException;
import com.wisemapping.exceptions.PasswordTooLongException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.AuthenticationType;
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.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.security.authentication.AuthenticationManager;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/api/restful/users")
public class UserController extends BaseController {
@Qualifier("userService")
@Autowired
private UserService userService;
@Autowired
private RecaptchaService captchaService;
@Qualifier("authenticationManager")
@Autowired
private AuthenticationManager authManager;
@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 = "/", produces = {"application/json"})
@ResponseStatus(value = HttpStatus.CREATED)
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);
if (remoteIp == null || remoteIp.isEmpty()) {
remoteIp = request.getRemoteAddr();
}
logger.debug("Remote address" + remoteIp);
verify(registration, remoteIp);
final Account user = new Account();
user.setEmail(registration.getEmail().trim());
user.setFirstname(registration.getFirstname());
user.setLastname(registration.getLastname());
user.setPassword(registration.getPassword());
user.setAuthenticationType(AuthenticationType.DATABASE);
userService.createUser(user, false, true);
response.setHeader("Location", "/api/restful/users/" + user.getId());
response.setHeader("ResourceId", Integer.toString(user.getId()));
}
@RequestMapping(method = RequestMethod.PUT, value = "/resetPassword", produces = {"application/json"})
@ResponseStatus(value = HttpStatus.OK)
public RestResetPasswordResponse resetPassword(@RequestParam String email) throws InvalidAuthSchemaException, EmailNotExistsException {
try {
return userService.resetPassword(email);
} catch (InvalidUserEmailException e) {
throw new EmailNotExistsException(e);
}
}
private void verify(@NotNull final RestUserRegistration registration, @NotNull String remoteAddress)
throws BindException {
final BindException errors = new RegistrationException(registration, "registration");
final UserValidator validator = new UserValidator();
validator.setUserService(userService);
validator.validate(registration, errors);
// If captcha is enabled, generate it ...
if (registrationCaptchaEnabled) {
final String recaptcha = registration.getRecaptcha();
if (recaptcha != null) {
final String reCaptchaResponse = captchaService.verifyRecaptcha(remoteAddress, recaptcha);
if (reCaptchaResponse != null && !reCaptchaResponse.isEmpty()) {
errors.rejectValue("recaptcha", reCaptchaResponse);
}
} else {
errors.rejectValue("recaptcha", Messages.CAPTCHA_LOADING_ERROR);
}
} else {
logger.warn("captchaEnabled is enabled.Recommend to enable it for production environments.");
}
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

@ -30,9 +30,6 @@ import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import java.util.*;
@JsonAutoDetect(
@ -47,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
@ -67,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) {
@ -78,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) {
@ -123,7 +120,7 @@ public class RestErrors {
@Nullable
public String getGlobalSeverity() {
return this.gSeverity.toString();
return this.globalSeverity.toString();
}
@Nullable
@ -132,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,9 +1,27 @@
/*
* 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;
@ -20,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();
}
@ -56,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,7 +1,7 @@
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 jakarta.xml.bind.annotation.XmlElement;
@ -20,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,7 +21,7 @@ package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
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;
@ -40,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();
}

View File

@ -29,9 +29,6 @@ import com.wisemapping.util.TimeUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import java.io.IOException;
import java.util.Calendar;
@ -103,7 +100,7 @@ public class RestMindmap {
}
public String getCreator() {
final User creator = mindmap.getCreator();
final Account creator = mindmap.getCreator();
return creator != null ? creator.getEmail() : null;
}
@ -112,7 +109,7 @@ public class RestMindmap {
public RestCollaborator getLastModifierUser() {
final User lastEditor = mindmap.getLastEditor();
final Account lastEditor = mindmap.getLastEditor();
RestCollaborator result = null;
if (lastEditor != null && mindmap.hasPermissions(collaborator, CollaborationRole.EDITOR)) {
@ -155,7 +152,7 @@ public class RestMindmap {
}
public String getOwner() {
final User owner = mindmap.getCreator();
final Account owner = mindmap.getCreator();
return owner != null ? owner.getEmail() : null;
}

View File

@ -22,7 +22,7 @@ package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.wisemapping.model.MindMapHistory;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import org.jetbrains.annotations.NotNull;
import java.text.SimpleDateFormat;
@ -55,7 +55,7 @@ public class RestMindmapHistory {
public RestMindmapHistory(@NotNull MindMapHistory history) {
this.id = history.getId();
this.creation = history.getCreationTime();
final User editor = history.getEditor();
final Account editor = history.getEditor();
this.creator = editor != null ? editor.getFullName() : "";
}

View File

@ -92,7 +92,7 @@ public class RestMindmapInfo {
// Support test deserialization...
Set<RestLabel> result = this.restLabels;
if (result == null) {
final User me = Utils.getUser();
final Account me = Utils.getUser();
result = mindmap.getLabels().
stream()
.filter(l -> l.getCreator().equals(me))
@ -119,7 +119,7 @@ public class RestMindmapInfo {
}
public String getCreator() {
final User creator = mindmap.getCreator();
final Account creator = mindmap.getCreator();
return creator != null ? creator.getFullName() : null;
}
@ -132,7 +132,7 @@ public class RestMindmapInfo {
}
public String getRole() {
final User user = Utils.getUser();
final Account user = Utils.getUser();
String result;
final Optional<Collaboration> collaboration = mindmap.findCollaboration(user);
return collaboration.map(value -> value.getRole().getLabel()).orElse(ROLE_NONE);
@ -143,7 +143,7 @@ public class RestMindmapInfo {
}
public String getLastModifierUser() {
final User user = mindmap.getLastEditor();
final Account user = mindmap.getLastEditor();
return user != null ? user.getFullName() : "unknown";
}

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.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY
)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestMindmapMetadata {
private String jsonProps;
private boolean locked;
private String title;
private String isLockedBy;
private String creatorFullName;
public RestMindmapMetadata(@NotNull String title, @NotNull String jsonProps, @NotNull String creatorFullName, boolean locked, @Nullable String isLockedBy) {
this.jsonProps = jsonProps;
this.title = title;
this.locked = locked;
this.isLockedBy = isLockedBy;
this.creatorFullName = creatorFullName;
}
public String getJsonProps() {
return jsonProps;
}
public void setJsonProps(String jsonProps) {
this.jsonProps = jsonProps;
}
public boolean isLocked() {
return locked;
}
public void setLocked(boolean locked) {
this.locked = locked;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getIsLockedBy() {
return isLockedBy;
}
public void setIsLockedBy(String isLockedBy) {
this.isLockedBy = isLockedBy;
}
public String getCreatorFullName() {
return creatorFullName;
}
public void setCreatorFullName(String creatorFullName) {
this.creatorFullName = creatorFullName;
}
}

View File

@ -0,0 +1,61 @@
package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.wisemapping.model.Account;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY
)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestOath2CallbackResponse {
private String email;
private Boolean googleSync;
private String syncCode;
private String jwtToken;
public RestOath2CallbackResponse(@NotNull Account user, @Nullable String jwtToken) {
this.setEmail(user.getEmail());
this.setGoogleSync(user.getGoogleSync());
this.setSyncCode(user.getSyncCode());
this.setJwtToken(jwtToken);
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getGoogleSync() {
return googleSync;
}
public void setGoogleSync(Boolean googleSync) {
this.googleSync = googleSync;
}
public String getSyncCode() {
return syncCode;
}
public void setSyncCode(String syncCode) {
this.syncCode = syncCode;
}
public String getJwtToken() {
return jwtToken;
}
public void setJwtToken(String jwtToken) {
this.jwtToken = jwtToken;
}
}

View File

@ -24,7 +24,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.wisemapping.model.AuthenticationType;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
@ -38,14 +38,14 @@ import java.util.Calendar;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class RestUser {
private final User user;
private final Account user;
private String password;
public RestUser() {
this(new User());
this(new Account());
}
public RestUser(@NotNull User user) {
public RestUser(@NotNull Account user) {
this.user = user;
}
@ -99,7 +99,7 @@ public class RestUser {
}
@JsonIgnore
public User getDelegated() {
public Account getDelegated() {
return this.user;
}

View File

@ -22,7 +22,7 @@ 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.User;
import com.wisemapping.model.Account;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
@ -38,8 +38,8 @@ public class RestUserRegistration {
private String recaptcha;
@JsonIgnore
public User build() {
final User user = new User();
public Account build() {
final Account user = new Account();
user.setFirstname(firstname);
user.setLastname(lastname);
user.setEmail(email);
@ -47,6 +47,15 @@ public class RestUserRegistration {
return user;
}
public static RestUserRegistration create(String email, String password, String firstname, String lastname) {
final RestUserRegistration result = new RestUserRegistration();
result.email = email;
result.password = password;
result.firstname = firstname;
result.lastname = lastname;
return result;
}
public String getEmail() {
return email;
}

View File

@ -19,7 +19,7 @@
package com.wisemapping.security;
import com.wisemapping.model.User;
import com.wisemapping.model.Account;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -39,7 +39,7 @@ public class AuthenticationProvider implements org.springframework.security.auth
final String email = auth.getName();
final UserDetails userDetails = getUserDetailsService().loadUserByUsername(email);
final User user = userDetails.getUser();
final Account user = userDetails.getUser();
final String credentials = (String) auth.getCredentials();
if (user == null || credentials == null || !encoder.matches(user.getPassword(), credentials)) {

View File

@ -28,7 +28,7 @@ public class DefaultPasswordEncoderFactories {
public static final String ENCODING_ID = "bcrypt";
static PasswordEncoder createDelegatingPasswordEncoder() {
public static PasswordEncoder createDelegatingPasswordEncoder() {
final Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put(ENCODING_ID, new BCryptPasswordEncoder(12));

View File

@ -0,0 +1,59 @@
package com.wisemapping.security;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import com.wisemapping.model.Account;
public class GoogleAuthenticationProvider implements org.springframework.security.authentication.AuthenticationProvider {
private UserDetailsService userDetailsService;
public GoogleAuthenticationProvider(@NotNull UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
/**
* Authenticate the given PreAuthenticatedAuthenticationToken.
* <p>
* If the principal contained in the authentication object is null, the request will
* be ignored to allow other providers to authenticate it.
*/
@Override
public Authentication authenticate(Authentication inputToken) throws AuthenticationException {
if (!supports(inputToken.getClass())) {
return null;
}
if (inputToken.getPrincipal() == null) {
throw new BadCredentialsException("No pre-authenticated principal found in request.");
}
UserDetails userDetails = userDetailsService.loadUserByUsername(inputToken.getName());
final Account user = userDetails.getUser();
if (!user.isActive()) {
throw new BadCredentialsException("User has been disabled for login " + inputToken.getName());
}
PreAuthenticatedAuthenticationToken resultToken = new PreAuthenticatedAuthenticationToken(userDetails,
inputToken.getCredentials(), userDetails.getAuthorities());
resultToken.setDetails(userDetails);
userDetailsService.getUserService().auditLogin(user);
return resultToken;
}
/**
* Indicate that this provider only supports PreAuthenticatedAuthenticationToken
* (sub)classes.
*/
@Override
public final boolean supports(Class<?> authentication) {
return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
}
}

View File

@ -0,0 +1,87 @@
package com.wisemapping.security;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.security.Key;
import java.util.Date;
@Component
public class JwtTokenUtil implements Serializable {
final private Logger logger = LogManager.getLogger();
public final static String BEARER_TOKEN_PREFIX = "Bearer ";
@Value("${app.jwt.secret}")
private String jwtSecret;
@Value("${app.jwt.expirationMin}")
private int jwtExpirationMin;
@Autowired
private UserDetailsService userDetailsService;
public String generateJwtToken(@NotNull final UserDetails user) {
return Jwts.builder()
.setSubject((user.getUsername()))
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMin * 1000L * 60))
.signWith(key(), SignatureAlgorithm.HS256)
.compact();
}
private Key key() {
return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret));
}
@Nullable
public String extractFromJwtToken(String token) {
return Jwts.parserBuilder().setSigningKey(key()).build()
.parseClaimsJws(token).getBody().getSubject();
}
public boolean validateJwtToken(@NotNull String authToken) {
boolean result = false;
try {
Jwts.parserBuilder().setSigningKey(key()).build().parse(authToken);
result = true;
} catch (MalformedJwtException e) {
logger.error("Invalid JWT token: {}", e.getMessage());
} catch (ExpiredJwtException e) {
logger.error("JWT token is expired: {}", e.getMessage());
} catch (UnsupportedJwtException e) {
logger.error("JWT token is unsupported: {}", e.getMessage());
} catch (IllegalArgumentException e) {
logger.error("JWT claims string is empty: {}", e.getMessage());
}
logger.trace("Is JWT token valid:" + result);
return result;
}
@NotNull
public String doLogin(@NotNull HttpServletResponse response, @NotNull String email) {
logger.debug("Performing login:" + email);
final UserDetails userDetails = userDetailsService.loadUserByUsername(email);
// Add JWT in the HTTP header ...
final String token = generateJwtToken(userDetails);
response.addHeader(HttpHeaders.AUTHORIZATION, BEARER_TOKEN_PREFIX + token);
return token;
}
}

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