mirror of
https://bitbucket.org/wisemapping/wisemapping-open-source.git
synced 2024-11-15 03:07:55 +01:00
Merge branch 'develop'
This commit is contained in:
commit
41ea26e0a3
23
README.md
23
README.md
@ -58,6 +58,29 @@ Check out the [docker section](./docker/README.)
|
||||
Individual test result reports can be found in wisemapping-open-source/wise-webapp/target/failsafe-reports/index.html
|
||||
Test coverage report of unit and integration test can be found in wisemapping-open-source/wise-webapp/target/site/jacoco and wisemapping-open-source/wise-webapp/target/site/jacoco-it folders. Coverage report is generated in the verify phase of [lifecicle](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#introduction-to-the-build-lifecyclea) using [jacoco](https://www.jacoco.org/jacoco/trunk/doc/maven.html)
|
||||
|
||||
|
||||
## Google authorization
|
||||
|
||||
You must configure the following wisemapping properties (app.properties) in order to get google authorization working
|
||||
* `security.oauth2.google.callbackUrl`: url where google will redirect after user authentication, tipically {frontendBaseUrl}/c/registration-google. Also, this url must be defined in google app configuration
|
||||
* `security.oauth2.google.clientId`: client id from google app
|
||||
* `security.oauth2.google.clientSecret`: client secret from google app
|
||||
|
||||
You must create a Google Application in [Google Cloud](https://console.cloud.google.com) and complete all the information required by Google. Here are the most important properties.
|
||||
|
||||
Oauth consent screen
|
||||
* Authorized domains: wisemapping domain (ex: wisemapping.com), and you can add domains of other environments if needed
|
||||
* Permissions
|
||||
* `https://www.googleapis.com/auth/userinfo.profile`
|
||||
* `https://www.googleapis.com/auth/userinfo.email`
|
||||
* Test users: emails for testing, those can be used before the application is validated by Google
|
||||
|
||||
After that, in Credentials, you must create an `Oauth Client Id` credential
|
||||
* Authorized JavaScript origins: list of authorized domains from which to redirect to Google. Ex: `https://wisemaping.com`, `https://wisemapping-testing.com:8080`
|
||||
* Authorized redirect URIs: list of allowed urls to which google will redirect after authenticating . Ex: `https://wisemaping.com/c/registration-google`, `https://wisemapping-testing.com:8080/c/registration-google`
|
||||
|
||||
After credential was created, Google will show you the clientId and clientSecret to configure your application. For productive applications, you must **publish** your application, this is a validation process with Google.
|
||||
|
||||
## Members
|
||||
|
||||
### Founders
|
||||
|
@ -15,6 +15,9 @@ CREATE TABLE USER (
|
||||
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)
|
||||
);
|
||||
|
||||
|
@ -25,6 +25,9 @@ CREATE TABLE USER (
|
||||
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
|
||||
|
@ -15,6 +15,9 @@ CREATE TABLE "user" (
|
||||
activation_date DATE,
|
||||
allow_send_email TEXT NOT NULL DEFAULT 0,
|
||||
locale VARCHAR(5),
|
||||
google_sync BOOLEAN,
|
||||
sync_code VARCHAR(255),
|
||||
google_token VARCHAR(255),
|
||||
FOREIGN KEY (colaborator_id) REFERENCES COLLABORATOR (id) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
);
|
||||
|
||||
@ -27,14 +30,6 @@ CREATE TABLE LABEL (
|
||||
--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 (
|
||||
id SERIAL NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
@ -44,11 +39,17 @@ CREATE TABLE MINDMAP (
|
||||
creation_date TIMESTAMP,
|
||||
edition_date TIMESTAMP,
|
||||
creator_id INTEGER NOT NULL,
|
||||
tags VARCHAR(1014),
|
||||
last_editor_id INTEGER NOT NULL --,
|
||||
--FOREIGN KEY(creator_id) REFERENCES "USER"(colaborator_id) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
);
|
||||
|
||||
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 SERIAL NOT NULL PRIMARY KEY,
|
||||
@ -77,14 +78,6 @@ CREATE TABLE COLLABORATION (
|
||||
FOREIGN KEY (properties_id) REFERENCES COLLABORATION_PROPERTIES (id) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
);
|
||||
|
||||
CREATE TABLE TAG (
|
||||
id SERIAL NOT NULL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
user_id INTEGER NOT NULL --,
|
||||
--FOREIGN KEY(user_id) REFERENCES "USER"(colaborator_id) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE ACCESS_AUDITORY (
|
||||
id SERIAL NOT NULL PRIMARY KEY,
|
||||
login_date DATE,
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Based on ubuntu:latest, installs WiseMapping (http://ww.wisemapping.org)
|
||||
|
||||
# Based info setup ...
|
||||
FROM tomcat:9.0-jdk17-openjdk
|
||||
FROM tomcat:jdk17
|
||||
LABEL maintainer="Paulo Gustavo Veiga <pveiga@wisemapping.com>"
|
||||
|
||||
# Build variables ...
|
||||
@ -31,6 +31,9 @@ RUN sed -i 's|\
|
||||
</Host>|' \
|
||||
/usr/local/tomcat/conf/server.xml
|
||||
|
||||
RUN sed -i 's|<Context>|<Context>\
|
||||
<Loader jakartaConverter="TOMCAT" />|' \
|
||||
/usr/local/tomcat/conf/context.xml
|
||||
# Copy default HSQL DB for testing ...
|
||||
RUN mkdir -p ${DB_BASE_DIR}/db
|
||||
COPY db/ ${DB_BASE_DIR}/db
|
||||
|
@ -42,7 +42,7 @@ Depending on the database your want to configure, you can create initialization
|
||||
The next step is configure the WiseMapping for the database and credentials.
|
||||
Download `app.properties` configuration file and configure the required sections:
|
||||
|
||||
> $ curl https://bitbucket.org/wisemapping/wisemapping-open-source/raw/644b7078d790220c7844b732a83d45495f11d64e/wise-webapp/src/main/webapp/WEB-INF/app.properties
|
||||
> $ curl https://bitbucket.org/wisemapping/wisemapping-open-source/src/master/wise-webapp/src/main/webapp/WEB-INF/app.properties
|
||||
|
||||
### Starting the application
|
||||
|
||||
|
@ -25,6 +25,9 @@ CREATE TABLE USER (
|
||||
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
|
||||
@ -113,17 +116,6 @@ CREATE TABLE COLLABORATION (
|
||||
)
|
||||
CHARACTER SET utf8;
|
||||
|
||||
CREATE TABLE TAG (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
name VARCHAR(255)
|
||||
CHARACTER SET utf8 NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES USER (colaborator_id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE NO ACTION
|
||||
)
|
||||
CHARACTER SET utf8;
|
||||
|
||||
CREATE TABLE ACCESS_AUDITORY (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
login_date DATE,
|
||||
|
4
distribution/registration-google/update-db-mysql.sql
Normal file
4
distribution/registration-google/update-db-mysql.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE USER
|
||||
ADD COLUMN `google_sync` TINYINT(1) NULL,
|
||||
ADD COLUMN `sync_code` VARCHAR(255) NULL,
|
||||
ADD COLUMN `google_token` VARCHAR(255) NULL;
|
4
distribution/registration-google/update-db-postgres.sql
Normal file
4
distribution/registration-google/update-db-postgres.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE "user"
|
||||
ADD COLUMN `google_sync` BOOLEAN NULL,
|
||||
ADD COLUMN `sync_code` VARCHAR(255) NULL,
|
||||
ADD COLUMN `google_token` VARCHAR(255) NULL;
|
4
pom.xml
4
pom.xml
@ -4,7 +4,7 @@
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<properties>
|
||||
<com.wisemapping.version>5.0.14</com.wisemapping.version>
|
||||
<com.wisemapping.version>5.0.19</com.wisemapping.version>
|
||||
<superpom.dir>${project.basedir}/wise-webapps</superpom.dir>
|
||||
</properties>
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
<groupId>org.wisemapping</groupId>
|
||||
<artifactId>wisemapping</artifactId>
|
||||
<name>WiseMapping Project</name>
|
||||
<version>5.0.14</version>
|
||||
<version>5.0.19</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<licenses>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<groupId>org.wisemapping</groupId>
|
||||
<artifactId>wisemapping</artifactId>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<version>5.0.14</version>
|
||||
<version>5.0.19</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
@ -29,11 +29,11 @@
|
||||
<mkdir dir="target/wisemapping-mindplot"/>
|
||||
<exec executable="npm" dir="target" failonerror="true">
|
||||
<arg value="pack"/>
|
||||
<arg value="@wisemapping/mindplot@5.0.17"/>
|
||||
<arg value="@wisemapping/mindplot@5.0.19"/>
|
||||
</exec>
|
||||
<exec executable="tar" dir="target" failonerror="true">
|
||||
<arg value="-xvzf"/>
|
||||
<arg value="wisemapping-mindplot-5.0.17.tgz"/>
|
||||
<arg value="wisemapping-mindplot-5.0.19.tgz"/>
|
||||
<arg value="-C"/>
|
||||
<arg value="wisemapping-mindplot"/>
|
||||
</exec>
|
||||
@ -42,11 +42,11 @@
|
||||
<mkdir dir="target/wisemapping-webapp"/>
|
||||
<exec executable="npm" dir="target" failonerror="true">
|
||||
<arg value="pack"/>
|
||||
<arg value="@wisemapping/webapp@5.0.18"/>
|
||||
<arg value="@wisemapping/webapp@5.0.19"/>
|
||||
</exec>
|
||||
<exec executable="tar" dir="target" failonerror="true">
|
||||
<arg value="-xvzf"/>
|
||||
<arg value="wisemapping-webapp-5.0.18.tgz"/>
|
||||
<arg value="wisemapping-webapp-5.0.19.tgz"/>
|
||||
<arg value="-C"/>
|
||||
<arg value="wisemapping-webapp"/>
|
||||
</exec>
|
||||
|
@ -1,4 +1,5 @@
|
||||
<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">
|
||||
<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>
|
||||
<artifactId>wise-webapp</artifactId>
|
||||
<packaging>war</packaging>
|
||||
@ -8,13 +9,13 @@
|
||||
<groupId>org.wisemapping</groupId>
|
||||
<artifactId>wisemapping</artifactId>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<version>5.0.14</version>
|
||||
<version>5.0.19</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<org.springframework.version>5.3.22</org.springframework.version>
|
||||
<org.springframework.addons>5.6.2</org.springframework.addons>
|
||||
<hibernate.version>5.6.11.Final</hibernate.version>
|
||||
<org.springframework.version>5.3.24</org.springframework.version>
|
||||
<org.springframework.addons>5.7.3</org.springframework.addons>
|
||||
<hibernate.version>5.6.12.Final</hibernate.version>
|
||||
<hibernate-validator.version>6.0.21.Final</hibernate-validator.version>
|
||||
<spring-security-taglibs.version>5.6.1</spring-security-taglibs.version>
|
||||
</properties>
|
||||
@ -41,7 +42,7 @@
|
||||
<dependency>
|
||||
<groupId>com.intellij</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>7.0.3</version>
|
||||
<version>12.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -50,6 +51,11 @@
|
||||
<version>${org.springframework.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
@ -195,7 +201,7 @@
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.28</version>
|
||||
<version>8.0.31</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -219,10 +225,9 @@
|
||||
<version>3.9.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
<scope>compile</scope>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.19.0</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
|
||||
<dependency>
|
||||
@ -240,7 +245,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.13.1</version>
|
||||
<version>2.13.4.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- This is required in case of Tomcat, do not remove -->
|
||||
@ -291,15 +296,10 @@
|
||||
</configuration>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.6.1</version>
|
||||
<version>2.7.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@ -343,7 +343,7 @@
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.5</version>
|
||||
<version>8.0.31</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@ -559,7 +559,9 @@
|
||||
<daemon>true</daemon>
|
||||
<waitForChild>false</waitForChild>
|
||||
<maxStartupLines>200</maxStartupLines>
|
||||
<jvmArgs>${integrationTestArgLine} -Ddatabase.base.url=${project.build.directory} -Djetty.port=8080</jvmArgs>
|
||||
<jvmArgs>${integrationTestArgLine} -Ddatabase.base.url=${project.build.directory}
|
||||
-Djetty.port=8080
|
||||
</jvmArgs>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
|
@ -19,6 +19,7 @@
|
||||
package com.wisemapping.dao;
|
||||
|
||||
import com.wisemapping.model.AccessAuditory;
|
||||
import com.wisemapping.model.AuthenticationType;
|
||||
import com.wisemapping.model.Collaboration;
|
||||
import com.wisemapping.model.Collaborator;
|
||||
import com.wisemapping.model.User;
|
||||
@ -31,7 +32,6 @@ import org.springframework.orm.hibernate5.HibernateTemplate;
|
||||
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
@ -101,7 +101,11 @@ public class UserManagerImpl
|
||||
@Override
|
||||
public void createUser(User 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("");
|
||||
}
|
||||
getHibernateTemplate().saveOrUpdate(user);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* If your wisemapping customization throws cross domain errores in browser, you can configure this filter in webdefault.xml
|
||||
* By default it will accept all domains, but you can restrict to the domain you need
|
||||
*
|
||||
* <filter>
|
||||
* <filter-name>cross-origin</filter-name>
|
||||
* <filter-class>com.wisemapping.filter.CorsFilter</filter-class>
|
||||
* <init-param>
|
||||
* <param-name>allowedOrigins</param-name>
|
||||
* <param-value>*</param-value>
|
||||
* </init-param>
|
||||
* <init-param>
|
||||
* <param-name>allowedMethods</param-name>
|
||||
* <param-value>GET,POST,HEAD</param-value>
|
||||
* </init-param>
|
||||
* <init-param>
|
||||
* <param-name>allowedHeaders</param-name>
|
||||
* <param-value>X-Requested-With,Content-Type,Accept,Origin</param-value>
|
||||
* </init-param>
|
||||
* </filter>
|
||||
* <filter-mapping>
|
||||
* <filter-name>cross-origin</filter-name>
|
||||
* <url-pattern>/*</url-pattern>
|
||||
* </filter-mapping>
|
||||
*
|
||||
*/
|
||||
public class CorsFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
if (servletResponse != null) {
|
||||
// Authorize (allow) all domains to consume the content
|
||||
((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Origin", "*");
|
||||
((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Methods","GET, OPTIONS, HEAD, PUT, POST");
|
||||
}
|
||||
|
||||
chain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
}
|
@ -54,6 +54,9 @@ public class RequestPropertiesInterceptor implements HandlerInterceptor {
|
||||
@Value("${security.type}")
|
||||
private String securityType;
|
||||
|
||||
@Value("${security.oauth2.google.url}")
|
||||
private String googleOauth2Url;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, Object object) throws Exception {
|
||||
|
||||
@ -64,6 +67,8 @@ public class RequestPropertiesInterceptor implements HandlerInterceptor {
|
||||
request.setAttribute("google.recaptcha2.enabled", recaptcha2Enabled);
|
||||
request.setAttribute("google.recaptcha2.siteKey", recaptcha2SiteKey);
|
||||
|
||||
request.setAttribute("security.oauth2.google.url", googleOauth2Url);
|
||||
|
||||
request.setAttribute("site.homepage", siteHomepage);
|
||||
request.setAttribute("site.static.js.url", siteStaticUrl);
|
||||
|
||||
|
@ -24,8 +24,10 @@ import com.wisemapping.model.User;
|
||||
import com.wisemapping.security.Utils;
|
||||
import com.wisemapping.service.LockManager;
|
||||
import com.wisemapping.service.MindmapService;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
@ -34,7 +36,7 @@ import javax.servlet.http.HttpSessionEvent;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
|
||||
public class UnlockOnExpireListener implements HttpSessionListener {
|
||||
private static final Logger logger = Logger.getLogger(UnlockOnExpireListener.class);
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
@Override
|
||||
public void sessionCreated(@NotNull HttpSessionEvent event) {
|
||||
|
@ -24,7 +24,8 @@ import com.wisemapping.model.Mindmap;
|
||||
import com.wisemapping.model.User;
|
||||
import com.wisemapping.rest.model.RestLogItem;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
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;
|
||||
@ -42,7 +43,7 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
final public class NotificationService {
|
||||
final private static Logger logger = Logger.getLogger(Mailer.class);
|
||||
final private static Logger logger = LogManager.getLogger();
|
||||
private ResourceBundleMessageSource messageSource;
|
||||
|
||||
@Autowired
|
||||
|
@ -23,7 +23,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
public enum AuthenticationType {
|
||||
DATABASE('D'),
|
||||
LDAP('L'),
|
||||
OPENID('O');
|
||||
GOOGLE_OAUTH2('G');
|
||||
|
||||
private final char schemaCode;
|
||||
|
||||
AuthenticationType(char schemaCode) {
|
||||
|
@ -19,13 +19,12 @@
|
||||
package com.wisemapping.model;
|
||||
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
@Table(name = "COLLABORATION")
|
||||
@ -127,16 +126,14 @@ public class Collaboration implements Serializable {
|
||||
Collaboration that = (Collaboration) o;
|
||||
|
||||
if (id != that.id) return false;
|
||||
if (collaborator != null ? !collaborator.equals(that.collaborator) : that.collaborator != null) return false;
|
||||
if (mindMap != null ? !mindMap.equals(that.mindMap) : that.mindMap != null) return false;
|
||||
if (!Objects.equals(collaborator, that.collaborator)) return false;
|
||||
if (!Objects.equals(mindMap, that.mindMap)) return false;
|
||||
return role == that.role;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = id ^ (id >>> 32);
|
||||
result = 31 * result + (role != null ? role.hashCode() : 0);
|
||||
result = 31 * result + (mindMap != null ? mindMap.hashCode() : 0);
|
||||
return result;
|
||||
//https://thorben-janssen.com/ultimate-guide-to-implementing-equals-and-hashcode-with-hibernate/
|
||||
return 13;
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ public class Collaborator implements Serializable {
|
||||
int id = this.getId();
|
||||
String email = this.getEmail();
|
||||
|
||||
int result = (int) (id ^ (id >>> 32));
|
||||
int result = id ^ (id >>> 32);
|
||||
result = 31 * result + (email != null ? email.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
@Table(name = "LABEL")
|
||||
@ -34,17 +35,22 @@ public class Label implements Serializable {
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private int id;
|
||||
|
||||
@NotNull private String title;
|
||||
@NotNull private String color;
|
||||
@Nullable private String iconName;
|
||||
@NotNull
|
||||
private String title;
|
||||
@NotNull
|
||||
private String color;
|
||||
@Nullable
|
||||
private String iconName;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "creator_id", nullable = true, unique = true)
|
||||
@NotNull private User creator;
|
||||
@NotNull
|
||||
private User creator;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "parent_label_id", nullable = true)
|
||||
@Nullable private Label parent;
|
||||
@Nullable
|
||||
private Label parent;
|
||||
|
||||
public void setParent(@Nullable Label parent) {
|
||||
this.parent = parent;
|
||||
@ -104,16 +110,14 @@ public class Label implements Serializable {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof Label)) return false;
|
||||
|
||||
Label label = (Label) o;
|
||||
|
||||
final Label label = (Label) o;
|
||||
return id == label.id && creator.getId() == label.creator.getId()
|
||||
&& !(parent != null ? !parent.equals(label.parent) : label.parent != null);
|
||||
&& Objects.equals(parent, label.parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
long result = id;
|
||||
result = 31 * result + title.hashCode();
|
||||
long result = title.hashCode();
|
||||
result = 31 * result + (creator != null ? creator.hashCode() : 0);
|
||||
result = 31 * result + (parent != null ? parent.hashCode() : 0);
|
||||
return (int) result;
|
||||
|
@ -83,13 +83,9 @@ public class Mindmap implements Serializable {
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private byte[] zippedXml;
|
||||
|
||||
//~ Constructors .........................................................................................
|
||||
|
||||
public Mindmap() {
|
||||
}
|
||||
|
||||
//~ Methods ..............................................................................................
|
||||
|
||||
public void setUnzipXml(@NotNull byte[] value) {
|
||||
try {
|
||||
final byte[] zip = ZipUtils.bytesToZip(value);
|
||||
@ -146,7 +142,9 @@ public class Mindmap implements Serializable {
|
||||
}
|
||||
|
||||
public void removedCollaboration(@NotNull Collaboration collaboration) {
|
||||
collaborations.remove(collaboration);
|
||||
// https://stackoverflow.com/questions/25125210/hibernate-persistentset-remove-operation-not-working
|
||||
this.collaborations.remove(collaboration);
|
||||
collaboration.setMindMap(null);
|
||||
}
|
||||
|
||||
public void removedCollaboration(@NotNull Set<Collaboration> collaborations) {
|
||||
@ -316,11 +314,20 @@ public class Mindmap implements Serializable {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
result.append("<map version=\"tango\">");
|
||||
result.append("<topic central=\"true\" text=\"");
|
||||
result.append(StringEscapeUtils.escapeXml(title));
|
||||
result.append(escapeXmlAttribute(title));
|
||||
result.append("\"/></map>");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
static private String escapeXmlAttribute(String attValue) {
|
||||
// Hack: Find out of the box function.
|
||||
String result = attValue.replace("&", "&");
|
||||
result = result.replace("<", "<");
|
||||
result = result.replace("gt", ">");
|
||||
result = result.replace("\"", """);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Mindmap shallowClone() {
|
||||
final Mindmap result = new Mindmap();
|
||||
result.setDescription(this.getDescription());
|
||||
@ -351,18 +358,6 @@ public class Mindmap implements Serializable {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Label findLabel(int labelId) {
|
||||
Label result = null;
|
||||
for (Label label : this.labels) {
|
||||
if (label.getId() == labelId) {
|
||||
result = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void removeLabel(@NotNull final Label label) {
|
||||
this.labels.remove(label);
|
||||
}
|
||||
|
@ -18,15 +18,12 @@
|
||||
|
||||
package com.wisemapping.model;
|
||||
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
@Table(name = "USER")
|
||||
@ -55,6 +52,15 @@ public class User
|
||||
@Column(name = "authenticator_uri")
|
||||
private String authenticatorUri;
|
||||
|
||||
@Column(name = "google_sync")
|
||||
private Boolean googleSync;
|
||||
|
||||
@Column(name = "sync_code")
|
||||
private String syncCode;
|
||||
|
||||
@Column(name = "google_token")
|
||||
private String googleToken;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
@ -151,6 +157,34 @@ public class User
|
||||
this.authenticatorUri = authenticatorUri;
|
||||
}
|
||||
|
||||
public void setAuthenticationTypeCode(Character authenticationTypeCode) {
|
||||
this.authenticationTypeCode = authenticationTypeCode;
|
||||
}
|
||||
|
||||
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 getGoogleToken() {
|
||||
return googleToken;
|
||||
}
|
||||
|
||||
public void setGoogleToken(String googleToken) {
|
||||
this.googleToken = googleToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" +
|
||||
|
@ -19,19 +19,15 @@
|
||||
package com.wisemapping.rest;
|
||||
|
||||
import com.wisemapping.exceptions.WiseMappingException;
|
||||
import com.wisemapping.mail.NotificationService;
|
||||
import com.wisemapping.model.Collaboration;
|
||||
import com.wisemapping.model.Label;
|
||||
import com.wisemapping.model.Mindmap;
|
||||
import com.wisemapping.model.User;
|
||||
import com.wisemapping.rest.model.RestLogItem;
|
||||
import com.wisemapping.rest.model.RestUser;
|
||||
import com.wisemapping.security.Utils;
|
||||
import com.wisemapping.service.LabelService;
|
||||
import com.wisemapping.service.MindmapService;
|
||||
import com.wisemapping.service.UserService;
|
||||
import org.apache.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;
|
||||
@ -41,7 +37,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
@ -58,10 +53,6 @@ public class AccountController extends BaseController {
|
||||
@Autowired
|
||||
private LabelService labelService;
|
||||
|
||||
@Autowired
|
||||
private NotificationService notificationService;
|
||||
|
||||
|
||||
@RequestMapping(method = RequestMethod.PUT, value = "account/password", consumes = {"text/plain"})
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
public void changePassword(@RequestBody String password) {
|
||||
|
@ -24,7 +24,8 @@ import com.wisemapping.model.User;
|
||||
import com.wisemapping.rest.model.RestErrors;
|
||||
import com.wisemapping.security.Utils;
|
||||
import com.wisemapping.service.RegistrationException;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@ -42,7 +43,7 @@ import java.util.Locale;
|
||||
|
||||
public class BaseController {
|
||||
|
||||
final private Logger logger = Logger.getLogger(BaseController.class);
|
||||
final private Logger logger = LogManager.getLogger();
|
||||
|
||||
@Qualifier("messageSource")
|
||||
@Autowired
|
||||
|
@ -25,7 +25,8 @@ import com.wisemapping.security.Utils;
|
||||
import com.wisemapping.service.*;
|
||||
import com.wisemapping.validator.MapInfoValidator;
|
||||
import org.apache.commons.validator.routines.EmailValidator;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@ -46,7 +47,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Controller
|
||||
public class MindmapController extends BaseController {
|
||||
final Logger logger = Logger.getLogger(MindmapController.class);
|
||||
final Logger logger = LogManager.getLogger();
|
||||
|
||||
private static final String LATEST_HISTORY_REVISION = "latest";
|
||||
|
||||
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.User;
|
||||
import com.wisemapping.rest.model.RestOath2CallbackResponse;
|
||||
import com.wisemapping.service.*;
|
||||
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.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
|
||||
@Controller
|
||||
@CrossOrigin
|
||||
public class Oauth2Controller extends BaseController {
|
||||
@Qualifier("userService")
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Qualifier("authenticationManager")
|
||||
@Autowired
|
||||
private AuthenticationManager authManager;
|
||||
|
||||
@Value("${google.recaptcha2.enabled}")
|
||||
private Boolean recatchaEnabled;
|
||||
|
||||
@Value("${accounts.exclusion.domain:''}")
|
||||
private String domainBanExclusion;
|
||||
|
||||
private void doLogin(HttpServletRequest request, String email) {
|
||||
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(email,null);
|
||||
Authentication auth = authManager.authenticate(token);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
// update spring mvc session
|
||||
HttpSession session = request.getSession(true);
|
||||
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, value = "/oauth2/googlecallback", produces = { "application/json" })
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public RestOath2CallbackResponse processGoogleCallback(@NotNull @RequestParam String code, @NotNull HttpServletRequest request) throws WiseMappingException {
|
||||
User user = userService.createUserFromGoogle(code);
|
||||
if (user.getGoogleSync() != null && user.getGoogleSync().booleanValue()) {
|
||||
doLogin(request, user.getEmail());
|
||||
}
|
||||
RestOath2CallbackResponse response = new RestOath2CallbackResponse();
|
||||
response.setEmail(user.getEmail());
|
||||
response.setGoogleSync(user.getGoogleSync());
|
||||
response.setSyncCode(user.getSyncCode());
|
||||
return response;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.PUT, value = "/oauth2/confirmaccountsync", produces = { "application/json" })
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public void confirmAccountSync(@NotNull @RequestParam String email, @NotNull @RequestParam String code, @NotNull HttpServletRequest request) throws WiseMappingException {
|
||||
userService.confirmAccountSync(email, code);
|
||||
doLogin(request, email);
|
||||
}
|
||||
|
||||
}
|
@ -22,22 +22,26 @@ import com.wisemapping.exceptions.EmailNotExistsException;
|
||||
import com.wisemapping.exceptions.WiseMappingException;
|
||||
import com.wisemapping.model.AuthenticationType;
|
||||
import com.wisemapping.model.User;
|
||||
import com.wisemapping.rest.model.RestResetPasswordResponse;
|
||||
import com.wisemapping.rest.model.RestUserRegistration;
|
||||
import com.wisemapping.service.*;
|
||||
import com.wisemapping.validator.Messages;
|
||||
import com.wisemapping.validator.UserValidator;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@ -51,18 +55,23 @@ public class UserController extends BaseController {
|
||||
@Autowired
|
||||
private RecaptchaService captchaService;
|
||||
|
||||
@Qualifier("authenticationManager")
|
||||
@Autowired
|
||||
private AuthenticationManager authManager;
|
||||
|
||||
@Value("${google.recaptcha2.enabled}")
|
||||
private Boolean recatchaEnabled;
|
||||
|
||||
@Value("${accounts.exclusion.domain:''}")
|
||||
private String domainBanExclusion;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(UserController.class);
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
private static final String REAL_IP_ADDRESS_HEADER = "X-Real-IP";
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, value = "/users", produces = { "application/json" })
|
||||
@ResponseStatus(value = HttpStatus.CREATED)
|
||||
public void registerUser(@RequestBody RestUserRegistration registration, @NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws WiseMappingException, BindException {
|
||||
public void registerUser(@RequestBody RestUserRegistration registration, @NotNull HttpServletRequest request,
|
||||
@NotNull HttpServletResponse response) throws WiseMappingException, BindException {
|
||||
logger.debug("Register new user:" + registration.getEmail());
|
||||
|
||||
// If tomcat is behind a reverse proxy, ip needs to be found in other header.
|
||||
@ -87,15 +96,16 @@ public class UserController extends BaseController {
|
||||
|
||||
@RequestMapping(method = RequestMethod.PUT, value = "/users/resetPassword", produces = { "application/json" })
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public void resetPassword(@RequestParam String email) throws InvalidAuthSchemaException, EmailNotExistsException {
|
||||
public RestResetPasswordResponse resetPassword(@RequestParam String email) throws InvalidAuthSchemaException, EmailNotExistsException {
|
||||
try {
|
||||
userService.resetPassword(email);
|
||||
return userService.resetPassword(email);
|
||||
} catch (InvalidUserEmailException e) {
|
||||
throw new EmailNotExistsException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void verify(@NotNull final RestUserRegistration registration, @NotNull String remoteAddress) throws BindException {
|
||||
private void verify(@NotNull final RestUserRegistration registration, @NotNull String remoteAddress)
|
||||
throws BindException {
|
||||
|
||||
final BindException errors = new RegistrationException(registration, "registration");
|
||||
final UserValidator validator = new UserValidator();
|
||||
@ -125,7 +135,9 @@ public class UserController extends BaseController {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
package com.wisemapping.rest.model;
|
||||
|
||||
public class RestOath2CallbackResponse {
|
||||
|
||||
private String email;
|
||||
private Boolean googleSync;
|
||||
private String syncCode;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.wisemapping.rest.model;
|
||||
|
||||
public enum RestResetPasswordAction {
|
||||
|
||||
EMAIL_SENT, OAUTH2_USER
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.wisemapping.rest.model;
|
||||
|
||||
public class RestResetPasswordResponse {
|
||||
|
||||
RestResetPasswordAction action;
|
||||
|
||||
public RestResetPasswordAction getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(RestResetPasswordAction action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
}
|
@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -102,6 +103,10 @@ public class RestUser {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
public AuthenticationType getAuthenticationType() {
|
||||
return user.getAuthenticationType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof RestUser)) {
|
||||
|
@ -0,0 +1,62 @@
|
||||
package com.wisemapping.security;
|
||||
|
||||
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.User;
|
||||
|
||||
public class GoogleAuthenticationProvider implements org.springframework.security.authentication.AuthenticationProvider {
|
||||
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
public UserDetailsService getUserDetailsService() {
|
||||
return userDetailsService;
|
||||
}
|
||||
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the given PreAuthenticatedAuthenticationToken.
|
||||
*
|
||||
* 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 User 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -18,7 +18,9 @@
|
||||
|
||||
package com.wisemapping.security;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.security.crypto.codec.Hex;
|
||||
import org.springframework.security.crypto.codec.Utf8;
|
||||
@ -29,7 +31,7 @@ import java.security.NoSuchAlgorithmException;
|
||||
|
||||
|
||||
public class LegacyPasswordEncoder implements PasswordEncoder {
|
||||
final private static Logger logger = Logger.getLogger(LegacyPasswordEncoder.class);
|
||||
final private static Logger logger = LogManager.getLogger();
|
||||
|
||||
public static final String ENC_PREFIX = "ENC:";
|
||||
private final ShaPasswordEncoder sha1Encoder = new ShaPasswordEncoder();
|
||||
|
@ -23,7 +23,6 @@ import com.wisemapping.model.User;
|
||||
import com.wisemapping.service.UserService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
|
@ -38,7 +38,6 @@ public class ViewBaseSecurityAdvise
|
||||
|
||||
@Override
|
||||
protected boolean isAllowed(@Nullable User user, Mindmap map) {
|
||||
System.out.println("VIEWWWWWWWWWWWWW");
|
||||
return getMindmapService().hasPermissions(user, map, CollaborationRole.VIEWER);
|
||||
}
|
||||
|
||||
|
@ -23,18 +23,21 @@ import com.wisemapping.exceptions.LockException;
|
||||
import com.wisemapping.model.CollaborationRole;
|
||||
import com.wisemapping.model.Mindmap;
|
||||
import com.wisemapping.model.User;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
class LockManagerImpl implements LockManager {
|
||||
private static final int ONE_MINUTE_MILLISECONDS = 1000 * 60;
|
||||
private final Map<Integer, LockInfo> lockInfoByMapId;
|
||||
private final static Timer expirationTimer = new Timer();
|
||||
final private static Logger logger = Logger.getLogger(LockManagerImpl.class);
|
||||
final private static Logger logger = LogManager.getLogger();
|
||||
|
||||
@Override
|
||||
public boolean isLocked(@NotNull Mindmap mindmap) {
|
||||
|
@ -143,15 +143,13 @@ public class MindmapServiceImpl
|
||||
public void removeCollaboration(@NotNull Mindmap mindmap, @NotNull Collaboration collaboration) throws CollaborationException {
|
||||
// remove collaborator association
|
||||
final Mindmap mindMap = collaboration.getMindMap();
|
||||
final Set<Collaboration> collaborations = mindMap.getCollaborations();
|
||||
|
||||
final User creator = mindMap.getCreator();
|
||||
if (creator.identityEquality(collaboration.getCollaborator())) {
|
||||
throw new CollaborationException("User is the creator and must have ownership permissions.Creator Email:" + mindMap.getCreator().getEmail() + ",Collaborator:" + collaboration.getCollaborator().getEmail());
|
||||
}
|
||||
|
||||
// When you delete an object from hibernate you have to delete it from *all* collections it exists in...
|
||||
collaborations.remove(collaboration);
|
||||
mindMap.removedCollaboration(collaboration);
|
||||
mindmapManager.removeCollaboration(collaboration);
|
||||
}
|
||||
|
||||
@ -249,7 +247,7 @@ public class MindmapServiceImpl
|
||||
|
||||
@Override
|
||||
public void revertChange(@NotNull Mindmap mindmap, int historyId)
|
||||
throws WiseMappingException, IOException {
|
||||
throws WiseMappingException {
|
||||
final MindMapHistory history = mindmapManager.getHistory(historyId);
|
||||
mindmap.setZippedXml(history.getZippedXml());
|
||||
updateMindmap(mindmap, true);
|
||||
|
@ -17,13 +17,15 @@
|
||||
*/
|
||||
package com.wisemapping.service;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.wisemapping.validator.Messages;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.fluent.Form;
|
||||
import org.apache.http.client.fluent.Request;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
@ -35,7 +37,7 @@ import java.util.Map;
|
||||
|
||||
public class RecaptchaService {
|
||||
|
||||
final private static Logger logger = Logger.getLogger(RecaptchaService.class);
|
||||
final private static Logger logger = LogManager.getLogger();
|
||||
final private static String GOOGLE_RECAPTCHA_VERIFY_URL =
|
||||
"https://www.google.com/recaptcha/api/siteverify";
|
||||
|
||||
|
@ -20,6 +20,8 @@ package com.wisemapping.service;
|
||||
|
||||
import com.wisemapping.exceptions.WiseMappingException;
|
||||
import com.wisemapping.model.User;
|
||||
import com.wisemapping.rest.model.RestResetPasswordResponse;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface UserService {
|
||||
@ -28,6 +30,10 @@ public interface UserService {
|
||||
|
||||
User createUser(@NotNull User user, boolean emailConfirmEnabled, boolean welcomeEmail) throws WiseMappingException;
|
||||
|
||||
User createUserFromGoogle(@NotNull String callbackCode) throws WiseMappingException;
|
||||
|
||||
User confirmAccountSync(@NotNull String email, @NotNull String code) throws WiseMappingException;
|
||||
|
||||
void changePassword(@NotNull User user);
|
||||
|
||||
User getUserBy(String email);
|
||||
@ -36,7 +42,7 @@ public interface UserService {
|
||||
|
||||
void updateUser(User user);
|
||||
|
||||
void resetPassword(@NotNull String email) throws InvalidUserEmailException, InvalidAuthSchemaException;
|
||||
RestResetPasswordResponse resetPassword(@NotNull String email) throws InvalidUserEmailException, InvalidAuthSchemaException;
|
||||
|
||||
void removeUser(@NotNull User user);
|
||||
|
||||
|
@ -23,6 +23,10 @@ import com.wisemapping.exceptions.InvalidMindmapException;
|
||||
import com.wisemapping.exceptions.WiseMappingException;
|
||||
import com.wisemapping.mail.NotificationService;
|
||||
import com.wisemapping.model.*;
|
||||
import com.wisemapping.rest.model.RestResetPasswordAction;
|
||||
import com.wisemapping.rest.model.RestResetPasswordResponse;
|
||||
import com.wisemapping.service.google.GoogleAccountBasicData;
|
||||
import com.wisemapping.service.google.GoogleService;
|
||||
import com.wisemapping.util.VelocityEngineUtils;
|
||||
import com.wisemapping.util.VelocityEngineWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -39,7 +43,7 @@ public class UserServiceImpl
|
||||
private NotificationService notificationService;
|
||||
private MessageSource messageSource;
|
||||
private VelocityEngineWrapper velocityEngineWrapper;
|
||||
|
||||
private GoogleService googleService;
|
||||
|
||||
@Override
|
||||
public void activateAccount(long code)
|
||||
@ -56,10 +60,15 @@ public class UserServiceImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPassword(@NotNull String email)
|
||||
public RestResetPasswordResponse resetPassword(@NotNull String email)
|
||||
throws InvalidUserEmailException, InvalidAuthSchemaException {
|
||||
final User user = userManager.getUserBy(email);
|
||||
if (user != null) {
|
||||
RestResetPasswordResponse response = new RestResetPasswordResponse();
|
||||
if (user.getAuthenticationType().equals(AuthenticationType.GOOGLE_OAUTH2)) {
|
||||
response.setAction(RestResetPasswordAction.OAUTH2_USER);
|
||||
return response;
|
||||
}
|
||||
|
||||
if (user.getAuthenticationType() != AuthenticationType.DATABASE) {
|
||||
throw new InvalidAuthSchemaException("Could not change password for " + user.getAuthenticationType().getCode());
|
||||
@ -72,6 +81,9 @@ public class UserServiceImpl
|
||||
|
||||
// Send an email with the new temporal password ...
|
||||
notificationService.resetPassword(user, password);
|
||||
|
||||
response.setAction(RestResetPasswordAction.EMAIL_SENT);
|
||||
return response;
|
||||
} else {
|
||||
throw new InvalidUserEmailException("The email '" + email + "' does not exists.");
|
||||
}
|
||||
@ -147,6 +159,55 @@ public class UserServiceImpl
|
||||
return user;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public User createUserFromGoogle(@NotNull String callbackCode) throws WiseMappingException {
|
||||
try {
|
||||
GoogleAccountBasicData data = googleService.processCallback(callbackCode);
|
||||
User existingUser = userManager.getUserBy(data.getEmail());
|
||||
if (existingUser == null) {
|
||||
User newUser = new User();
|
||||
// new registrations from google starts synched
|
||||
newUser.setGoogleSync(true);
|
||||
newUser.setEmail(data.getEmail());
|
||||
newUser.setFirstname(data.getName());
|
||||
newUser.setLastname(data.getLastName());
|
||||
newUser.setAuthenticationType(AuthenticationType.GOOGLE_OAUTH2);
|
||||
newUser.setGoogleToken(data.getAccessToken());
|
||||
existingUser = this.createUser(newUser, false, true);
|
||||
} else {
|
||||
// user exists and doesnt have confirmed account linking, I must wait for confirmation
|
||||
if (existingUser.getGoogleSync() == null) {
|
||||
existingUser.setGoogleSync(false);
|
||||
existingUser.setSyncCode(callbackCode);
|
||||
existingUser.setGoogleToken(data.getAccessToken());
|
||||
userManager.updateUser(existingUser);
|
||||
}
|
||||
|
||||
}
|
||||
return existingUser;
|
||||
} catch (Exception e) {
|
||||
throw new WiseMappingException("Cant create user", e);
|
||||
}
|
||||
}
|
||||
|
||||
public User confirmAccountSync(@NotNull String email, @NotNull String code) throws WiseMappingException {
|
||||
User existingUser = userManager.getUserBy(email);
|
||||
// additional security check
|
||||
if (existingUser == null || !existingUser.getSyncCode().equals(code)) {
|
||||
throw new WiseMappingException("User not found / incorrect code");
|
||||
}
|
||||
existingUser.setGoogleSync(true);
|
||||
existingUser.setSyncCode(null);
|
||||
// user will not be able to login again with usr/pwd schema
|
||||
existingUser.setAuthenticationType(AuthenticationType.GOOGLE_OAUTH2);
|
||||
existingUser.setPassword("");
|
||||
userManager.updateUser(existingUser);
|
||||
|
||||
return existingUser;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Mindmap buildTutorialMindmap(@NotNull String firstName) throws InvalidMindmapException {
|
||||
//To change body of created methods use File | Settings | File Templates.
|
||||
final Locale locale = LocaleContextHolder.getLocale();
|
||||
@ -209,6 +270,10 @@ public class UserServiceImpl
|
||||
this.velocityEngineWrapper = velocityEngineWrapper;
|
||||
}
|
||||
|
||||
public void setGoogleService(GoogleService googleService) {
|
||||
this.googleService = googleService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getCasUserBy(String uid) {
|
||||
// TODO Auto-generated method stub
|
||||
|
@ -0,0 +1,66 @@
|
||||
package com.wisemapping.service.google;
|
||||
|
||||
public class GoogleAccountBasicData {
|
||||
|
||||
private String email;
|
||||
private String accountId;
|
||||
private String name;
|
||||
private String lastName;
|
||||
private String accessToken;
|
||||
private String refreshToken;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public String getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public void setRefreshToken(String refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GoogleAccountBasicData [email=" + email + ", accountId=" + accountId + ", name=" + name + ", lastName="
|
||||
+ lastName + ", accessToken=" + accessToken + ", refreshToken=" + refreshToken + "]";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package com.wisemapping.service.google;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.wisemapping.service.http.HttpInvoker;
|
||||
import com.wisemapping.service.http.HttpInvokerContentType;
|
||||
import com.wisemapping.service.http.HttpInvokerException;
|
||||
import com.wisemapping.service.http.HttpMethod;
|
||||
|
||||
@Service
|
||||
public class GoogleService {
|
||||
private HttpInvoker httpInvoker;
|
||||
private String optinConfirmUrl;
|
||||
private String accountBasicDataUrl;
|
||||
private String clientId;
|
||||
private String clientSecret;
|
||||
private String callbackUrl;
|
||||
|
||||
public void setHttpInvoker(HttpInvoker httpInvoker) {
|
||||
this.httpInvoker = httpInvoker;
|
||||
}
|
||||
|
||||
public void setOptinConfirmUrl(String optinConfirmUrl) {
|
||||
this.optinConfirmUrl = optinConfirmUrl;
|
||||
}
|
||||
|
||||
public void setAccountBasicDataUrl(String accountBasicDataUrl) {
|
||||
this.accountBasicDataUrl = accountBasicDataUrl;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
public void setCallbackUrl(String callbackUrl) {
|
||||
this.callbackUrl = callbackUrl;
|
||||
}
|
||||
|
||||
private String getNodeAsString(JsonNode node, String fieldName) {
|
||||
return getNodeAsString(node, fieldName, null);
|
||||
}
|
||||
|
||||
private String getNodeAsString(JsonNode node, String fieldName, String defaultValue) {
|
||||
JsonNode subNode = node.get(fieldName);
|
||||
return subNode != null ? subNode.asText() : defaultValue;
|
||||
}
|
||||
|
||||
private Map<String, String> getHeaders(String token) {
|
||||
Map<String, String> headers = new HashMap<String, String>();
|
||||
headers.put("Content-type", "application/json");
|
||||
headers.put("Authorization", "Bearer " + token);
|
||||
return headers;
|
||||
}
|
||||
|
||||
private GoogleAccountBasicData getAccountBasicData(String token) throws HttpInvokerException {
|
||||
JsonNode response = httpInvoker.invoke(accountBasicDataUrl, null, HttpMethod.GET, this.getHeaders(token), null,
|
||||
null);
|
||||
GoogleAccountBasicData data = new GoogleAccountBasicData();
|
||||
data.setEmail(getNodeAsString(response, "email"));
|
||||
data.setAccountId(getNodeAsString(response, "id"));
|
||||
data.setName(getNodeAsString(response, "given_name", data.getEmail()));
|
||||
data.setLastName(getNodeAsString(response, "family_name"));
|
||||
return data;
|
||||
}
|
||||
|
||||
private Map<String, String> getOptinConfirmBody(String code) {
|
||||
Map<String, String> result = new HashMap<String, String>();
|
||||
result.put("client_id", clientId);
|
||||
result.put("client_secret", clientSecret);
|
||||
result.put("code", code);
|
||||
result.put("redirect_uri", callbackUrl);
|
||||
result.put("grant_type", "authorization_code");
|
||||
return result;
|
||||
}
|
||||
|
||||
public GoogleAccountBasicData processCallback(String code)
|
||||
throws HttpInvokerException, JsonMappingException, JsonProcessingException {
|
||||
Map<String, String> body = this.getOptinConfirmBody(code);
|
||||
JsonNode optinConfirmResponse = httpInvoker.invoke(
|
||||
optinConfirmUrl,
|
||||
HttpInvokerContentType.FORM_ENCODED,
|
||||
HttpMethod.POST,
|
||||
null,
|
||||
null,
|
||||
body);
|
||||
|
||||
String accessToken = getNodeAsString(optinConfirmResponse, "access_token");
|
||||
String refreshToken = getNodeAsString(optinConfirmResponse, "refresh_token");
|
||||
|
||||
GoogleAccountBasicData data = this.getAccountBasicData(accessToken);
|
||||
data.setAccessToken(accessToken);
|
||||
data.setRefreshToken(refreshToken);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
package com.wisemapping.service.http;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@Service
|
||||
public class HttpInvoker {
|
||||
|
||||
protected static Logger logger = LogManager.getLogger(HttpInvoker.class);
|
||||
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public HttpInvoker() {
|
||||
super();
|
||||
}
|
||||
|
||||
public JsonNode invoke(
|
||||
String url,
|
||||
HttpInvokerContentType requestContentType,
|
||||
HttpMethod method,
|
||||
Map<String, String> headers,
|
||||
String jsonPayload,
|
||||
Map<String, String> formData)
|
||||
throws HttpInvokerException {
|
||||
String responseBody = null;
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("finalUrl: " + url);
|
||||
logger.debug("method: " + method);
|
||||
logger.debug("payload: " + jsonPayload);
|
||||
logger.debug("header: " + headers);
|
||||
}
|
||||
|
||||
CloseableHttpClient httpClient = HttpClients.createDefault();
|
||||
HttpRequestBase httpRequst = null;
|
||||
|
||||
// build request
|
||||
if (method.equals(HttpMethod.POST))
|
||||
httpRequst = new HttpPost(url);
|
||||
else if (method.equals(HttpMethod.PUT))
|
||||
httpRequst = new HttpPut(url);
|
||||
else if (method.equals(HttpMethod.GET))
|
||||
httpRequst = new HttpGet(url);
|
||||
else if (method.equals(HttpMethod.DELETE))
|
||||
httpRequst = new HttpDelete(url);
|
||||
else
|
||||
throw new HttpInvokerException("Method " + method + " not suppoprted by http connector");
|
||||
|
||||
if (method.equals(HttpMethod.POST) || method.equals(HttpMethod.PUT)) {
|
||||
HttpEntity entity = null;
|
||||
if (requestContentType.equals(HttpInvokerContentType.JSON)) {
|
||||
if (jsonPayload == null)
|
||||
throw new HttpInvokerException("Json content is required");
|
||||
entity = new StringEntity(jsonPayload, Charset.forName("UTF-8"));
|
||||
((HttpEntityEnclosingRequestBase) httpRequst).setEntity(entity);
|
||||
}
|
||||
if (requestContentType.equals(HttpInvokerContentType.FORM_ENCODED)) {
|
||||
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
|
||||
Set<String> keys = formData.keySet();
|
||||
for (String key : keys) {
|
||||
nameValuePairs.add(new BasicNameValuePair(key, formData.get(key).toString()));
|
||||
}
|
||||
entity = new UrlEncodedFormEntity(nameValuePairs);
|
||||
((HttpEntityEnclosingRequestBase) httpRequst).setEntity(entity);
|
||||
}
|
||||
if (entity == null)
|
||||
throw new HttpInvokerException("Cant build entity to send");
|
||||
}
|
||||
|
||||
if (headers != null) {
|
||||
Set<String> keys = headers.keySet();
|
||||
for (String key : keys) {
|
||||
httpRequst.setHeader(key, headers.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
if (requestContentType != null)
|
||||
httpRequst.setHeader("Content-Type", requestContentType.getHttpContentType());
|
||||
|
||||
// invoke
|
||||
CloseableHttpResponse response = httpClient.execute(httpRequst);
|
||||
// response process
|
||||
JsonNode root = null;
|
||||
responseBody = response.getEntity() != null && response.getEntity().getContent() != null
|
||||
? IOUtils.toString(response.getEntity().getContent(), (String) null)
|
||||
: null;
|
||||
if (responseBody != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("response plain: " + responseBody);
|
||||
}
|
||||
try {
|
||||
root = mapper.readTree(responseBody);
|
||||
} catch (Exception e) {
|
||||
int returnCode = response.getStatusLine().getStatusCode();
|
||||
throw new HttpInvokerException("cant transform response to JSON. RQ: " + jsonPayload + ", RS: "
|
||||
+ responseBody + ", status: " + returnCode, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (response.getStatusLine().getStatusCode() >= 400) {
|
||||
logger.error("error response: " + responseBody);
|
||||
throw new HttpInvokerException("error invoking " + url + ", response: " + responseBody + ", status: "
|
||||
+ response.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
httpRequst.releaseConnection();
|
||||
response.close();
|
||||
httpClient.close();
|
||||
|
||||
return root;
|
||||
} catch (HttpInvokerException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.error("cant invoke service " + url);
|
||||
logger.error("response: " + responseBody, e);
|
||||
throw new HttpInvokerException("cant invoke service " + url, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.wisemapping.service.http;
|
||||
|
||||
public enum HttpInvokerContentType {
|
||||
|
||||
JSON("application/json"),
|
||||
FORM_ENCODED("application/x-www-form-urlencoded");
|
||||
|
||||
private String httpContentType;
|
||||
|
||||
private HttpInvokerContentType(String type) {
|
||||
this.httpContentType = type;
|
||||
}
|
||||
|
||||
public String getHttpContentType() {
|
||||
return httpContentType;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.wisemapping.service.http;
|
||||
|
||||
public class HttpInvokerException extends Exception {
|
||||
|
||||
public HttpInvokerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public HttpInvokerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.wisemapping.service.http;
|
||||
|
||||
public enum HttpMethod {
|
||||
POST, GET, DELETE, PUT
|
||||
}
|
@ -39,6 +39,11 @@ public class UsersController {
|
||||
return new ModelAndView("forgot-password");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "registration-google", method = RequestMethod.GET)
|
||||
public ModelAndView processGoogleCallback() {
|
||||
return new ModelAndView("registration-google");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "registration", method = RequestMethod.GET)
|
||||
public ModelAndView showRegistrationPage() {
|
||||
return new ModelAndView("registration");
|
||||
|
@ -68,3 +68,6 @@ SHARE_MAP.EMAIL_SUBJECT={0} hat eine Mindmap mit Ihnen geteilt
|
||||
EMAIL.DO_NOT_REPLAY=Wichtig: Antworten Sie nicht auf diese E-Mail. Wenn Sie weitere Hilfe benötigen oder Bedenken bezüglich Ihres Kontos haben, kontaktieren Sie uns <a href="mailto:{0}">hier</a>.
|
||||
EMAIL.GREETINGS=Hallo
|
||||
OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list.
|
||||
ZOOM_TO_FIT=Zum Beheben zoomen
|
||||
ZOOM_OUT=Rauszoomen
|
||||
ZOOM_IN=Hineinzoomen
|
@ -70,3 +70,6 @@ EMAIL.DO_NOT_REPLAY=Important: Do not reply this email. If you need further help
|
||||
EMAIL.GREETINGS=Hi
|
||||
TOO_MANY_INACTIVE_ACCOUNTS=You have shared your mindmaps to more than 20 user that have not registered yet. Please, remove inactive accounts or ask them to register.
|
||||
OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list.
|
||||
ZOOM_TO_FIT=Zoom to fit
|
||||
ZOOM_OUT=Zoom out
|
||||
ZOOM_IN=Zoom in
|
@ -68,3 +68,6 @@ SHARE_MAP.EMAIL_SUBJECT={0} te ha compartido un mapa mental
|
||||
EMAIL.DO_NOT_REPLAY=Importante: No responda este correo electrónico. Si necesita más ayuda o tiene alguna inquietud con respecto a su cuenta, comuníquese con nosotros a <a href="mailto:{0}">aquí</a>.
|
||||
EMAIL.GREETINGS=Hola
|
||||
OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list.
|
||||
ZOOM_TO_FIT=Centrar
|
||||
ZOOM_OUT=Alejar
|
||||
ZOOM_IN=Acercar
|
@ -68,3 +68,6 @@ SHARE_MAP.EMAIL_SUBJECT={0} a partagé une carte mentale avec vous
|
||||
EMAIL.DO_NOT_REPLAY=Important : Ne répondez pas à cet e-mail. Si vous avez besoin d'aide supplémentaire ou si vous avez des inquiétudes concernant votre compte, contactez-nous <a href="mailto:{0}">ici</a>.
|
||||
EMAIL.GREETINGS=Salut
|
||||
OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list.
|
||||
ZOOM_TO_FIT=Zoomer pour s'adapter
|
||||
ZOOM_OUT=Dézoomer
|
||||
ZOOM_IN=Agrandir
|
@ -134,11 +134,29 @@ security.ldap.auth.attribute=mail
|
||||
security.ldap.lastName.attribute=sn
|
||||
security.ldap.firstName.attribute=givenName
|
||||
|
||||
#######################################################################################
|
||||
# Google OAuth Authentication
|
||||
#######################################################################################
|
||||
# OAuth Client id
|
||||
#security.oauth2.google.clientId=<config settings>
|
||||
# OAuth Client secret
|
||||
#security.oauth2.google.clientSecret=<oauth client>
|
||||
# Redirect to this url, this url must be configured in the google app {baseurl}/c/registration-google
|
||||
#security.oauth2.google.callbackUrl=<oauth callback url>
|
||||
|
||||
# Google service for finish registration process, ie. exchange temporal code for user token
|
||||
security.oauth2.google.confirmUrl=https://oauth2.googleapis.com/token
|
||||
# Google service for get user data (name, email, etc)
|
||||
security.oauth2.google.userinfoUrl=https://www.googleapis.com/oauth2/v3/userinfo
|
||||
# Url for starting auth process with google
|
||||
security.oauth2.google.url=https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=${security.oauth2.google.callbackUrl}&prompt=consent&response_type=code&client_id=${security.oauth2.google.clientId}&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&state=wisemapping&include_granted_scopes=true
|
||||
|
||||
|
||||
|
||||
|
||||
#######################################################################################
|
||||
# User Account filtering policies
|
||||
#######################################################################################
|
||||
|
||||
# Coma separated list of domains and emails ban
|
||||
#accounts.exclusion.domain=
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
<definition name="login" template="/jsp/reactInclude.jsp"/>
|
||||
<definition name="registration" template="/jsp/reactInclude.jsp"/>
|
||||
<definition name="registration-google" template="/jsp/reactInclude.jsp"/>
|
||||
<definition name="forgot-password" template="/jsp/reactInclude.jsp"/>
|
||||
<definition name="mindmapList" template="/jsp/reactInclude.jsp"/>
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
<sec:authentication-manager alias="authenticationManager">
|
||||
<sec:authentication-provider ref="dbAuthenticationProvider" />
|
||||
<sec:authentication-provider ref="googleAuthenticationProvider" />
|
||||
<sec:authentication-provider user-service-ref="userDetailsService"/>
|
||||
</sec:authentication-manager>
|
||||
|
||||
@ -19,4 +20,7 @@
|
||||
<property name="userDetailsService" ref="userDetailsService"/>
|
||||
<property name="encoder" ref="passwordEncoder"/>
|
||||
</bean>
|
||||
<bean id="googleAuthenticationProvider" class="com.wisemapping.security.GoogleAuthenticationProvider">
|
||||
<property name="userDetailsService" ref="userDetailsService"/>
|
||||
</bean>
|
||||
</beans>
|
@ -7,6 +7,7 @@
|
||||
http://www.springframework.org/schema/security
|
||||
http://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<bean id="passwordEncoder" class="com.wisemapping.security.DefaultPasswordEncoderFactories" factory-method="createDelegatingPasswordEncoder"/>
|
||||
|
||||
<sec:authentication-manager>
|
||||
<sec:authentication-provider ref="ldapAuthProvider"/>
|
||||
|
@ -35,6 +35,9 @@
|
||||
<sec:intercept-url pattern="/service/users/" method="POST" access="permitAll"/>
|
||||
<sec:intercept-url pattern="/service/users/resetPassword" method="PUT" access="permitAll"/>
|
||||
|
||||
<sec:intercept-url pattern="/service/oauth2/googlecallback" method="POST" access="permitAll"/>
|
||||
<sec:intercept-url pattern="/service/oauth2/confirmaccountsync" method="PUT" access="permitAll"/>
|
||||
|
||||
<sec:intercept-url pattern="/service/admin/users/**" access="isAuthenticated() and hasRole('ROLE_ADMIN')"/>
|
||||
<sec:intercept-url pattern="/service/admin/database/**" access="isAuthenticated() and hasRole('ROLE_ADMIN')"/>
|
||||
<sec:intercept-url pattern="/service/**" access="isAuthenticated() and hasRole('ROLE_USER')"/>
|
||||
@ -47,6 +50,7 @@
|
||||
<sec:intercept-url pattern="/c/login" access="permitAll"/>
|
||||
<sec:intercept-url pattern="/c/registration" access="hasRole('ANONYMOUS')"/>
|
||||
<sec:intercept-url pattern="/c/registration-success" access="hasRole('ANONYMOUS')"/>
|
||||
<sec:intercept-url pattern="/c/registration-google" access="permitAll"/>
|
||||
<sec:intercept-url pattern="/c/forgot-password" access="hasRole('ANONYMOUS')"/>
|
||||
<sec:intercept-url pattern="/c/forgot-password-success" access="hasRole('ANONYMOUS')"/>
|
||||
|
||||
|
@ -18,12 +18,25 @@
|
||||
<property name="velocityEngineWrapper" ref="velocityEngineWrapper"/>
|
||||
</bean>
|
||||
|
||||
<bean id="httpInvoker" class="com.wisemapping.service.http.HttpInvoker">
|
||||
</bean>
|
||||
|
||||
<bean id="googleService" class="com.wisemapping.service.google.GoogleService">
|
||||
<property name="httpInvoker" ref="httpInvoker"/>
|
||||
<property name="optinConfirmUrl" value="${security.oauth2.google.confirmUrl}"/>
|
||||
<property name="accountBasicDataUrl" value="${security.oauth2.google.userinfoUrl}"/>
|
||||
<property name="clientId" value="${security.oauth2.google.clientId}"/>
|
||||
<property name="clientSecret" value="${security.oauth2.google.clientSecret}"/>
|
||||
<property name="callbackUrl" value="${security.oauth2.google.callbackUrl}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="userServiceTarget" class="com.wisemapping.service.UserServiceImpl">
|
||||
<property name="userManager" ref="userManager"/>
|
||||
<property name="mindmapService" ref="mindMapServiceTarget"/>
|
||||
<property name="notificationService" ref="notificationService"/>
|
||||
<property name="messageSource" ref="messageSource"/>
|
||||
<property name="velocityEngineWrapper" ref="velocityEngineWrapper"/>
|
||||
<property name="googleService" ref="googleService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
|
||||
|
@ -3,7 +3,7 @@
|
||||
/********************************************************************************/
|
||||
body {
|
||||
margin: 0;
|
||||
font-family:Arial;
|
||||
font-family:Montserrat;
|
||||
}
|
||||
|
||||
div#mindplot {
|
||||
|
@ -2,6 +2,8 @@
|
||||
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
|
||||
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
|
||||
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
|
||||
<%@ taglib uri = "http://java.sun.com/jsp/jstl/functions" prefix = "fn" %>
|
||||
|
||||
<%
|
||||
request.setAttribute("principal", com.wisemapping.security.Utils.getUser());
|
||||
%>
|
||||
|
@ -9,15 +9,13 @@
|
||||
<%--@elvariable id="lockInfo" type="com.wisemapping.service.LockInfo"--%>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="${fn:substring(locale,0,2)}">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta charset="utf-8" />
|
||||
<base href="${requestScope['site.baseurl']}/static/webapp/">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
|
||||
<link rel="stylesheet" media="print" onload="this.onload=null;this.removeAttribute('media');" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap"/>
|
||||
|
||||
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap" as="style" onload="this.onload=null;this.rel='stylesheet'" crossorigin>
|
||||
<%@ include file="/jsp/pageHeaders.jsf" %>
|
||||
|
||||
<title>Loading ... | WiseMapping</title>
|
||||
@ -47,8 +45,8 @@
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root" class="mindplot-root"></div>
|
||||
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/webapp/vendors.bundle.js" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/webapp/app.bundle.js" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/webapp/vendors.bundle.js" crossorigin="anonymous" defer></script>
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/webapp/app.bundle.js" crossorigin="anonymous" defer></script>
|
||||
|
||||
</body>
|
||||
|
||||
|
@ -5,17 +5,16 @@
|
||||
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<html lang="${fn:substring(locale,0,2)}">
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<base href="${requestScope['site.baseurl']}/static/mindplot/">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
|
||||
<link rel="stylesheet" media="print" onload="this.onload=null;this.removeAttribute('media');" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap"/>
|
||||
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap" as="style" onload="this.onload=null;this.rel='stylesheet'" crossorigin>
|
||||
<link rel="preload" href="../../css/viewonly.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
|
||||
<title>${mindmap.title} | <spring:message code="SITE.TITLE"/></title>
|
||||
<link rel="stylesheet" href="../../css/viewonly.css"/>
|
||||
<%@ include file="/jsp/pageHeaders.jsf" %>
|
||||
|
||||
<script type="text/javascript">
|
||||
@ -40,23 +39,6 @@
|
||||
</script>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${requestScope['google.analytics.enabled']}">
|
||||
<!-- Google Ads Sense Config. Lazy loading optimization -->
|
||||
<script type="text/javascript">
|
||||
function downloadJsAtOnload() {
|
||||
setTimeout(function downloadJs() {
|
||||
var element = document.createElement("script");
|
||||
element.setAttribute("data-ad-client", "ca-pub-4996113942657337");
|
||||
element.async = true;
|
||||
element.src = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js";
|
||||
document.body.appendChild(element);
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
window.addEventListener("load", downloadJsAtOnload, false);
|
||||
</script>
|
||||
</c:if>
|
||||
|
||||
<style>
|
||||
body {
|
||||
height: 100vh;
|
||||
@ -76,11 +58,11 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root" class="mindplot-root">
|
||||
<mindplot-component id="mindmap-comp"></mindplot-component>
|
||||
<mindplot-component id="mindmap-comp"/>
|
||||
</div>
|
||||
<div id="mindplot-tooltips" className="wise-editor"></div>
|
||||
|
||||
|
||||
<a href="${requestScope['site.homepage']}" target="new">
|
||||
<a href="${requestScope['site.homepage']}" target="new" aria-label="WiseMapping Homepage">
|
||||
<div id="footerLogo"></div>
|
||||
</a>
|
||||
|
||||
@ -89,24 +71,23 @@
|
||||
<span class="title"><spring:message code="DESCRIPTION"/>:</span><span>${mindmap.title}</span>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/mindplot/loader.js" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/mindplot/loader.js" crossorigin="anonymous" defer></script>
|
||||
|
||||
<div id="floating-panel">
|
||||
<div id="zoom-button">
|
||||
<button id="zoom-plus" title="Zoom Out">
|
||||
<img src="../../images/add.svg" width="24" height="24"/>
|
||||
<button id="zoom-plus" title="<spring:message code="ZOOM_IN"/>" alt="<spring:message code="ZOOM_IN"/>">
|
||||
<img src="../../images/add.svg" width="24" height="24" alt="<spring:message code="ZOOM_IN"/>"/>
|
||||
</button>
|
||||
<button id="zoom-minus" title="Zoom In">
|
||||
<img src="../../images/minus.svg" width="24" height="24"/>
|
||||
<button id="zoom-minus" title="<spring:message code="ZOOM_OUT"/>" alt="<spring:message code="ZOOM_OUT"/>">
|
||||
<img src="../../images/minus.svg" width="24" height="24" alt="<spring:message code="ZOOM_OUT"/>"/>
|
||||
</button>
|
||||
<div id="position">
|
||||
<button id="position-button" title="Center">
|
||||
<img src="../../images/center_focus.svg" width="24" height="24"/>
|
||||
<button id="position-button" title="<spring:message code="ZOOM_TO_FIT"/>" alt="<spring:message code="ZOOM_TO_FIT"/>">
|
||||
<img src="../../images/center_focus.svg" width="24" height="24" alt="<spring:message code="ZOOM_TO_FIT"/>"/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// Hook zoom events ...
|
||||
|
@ -1,18 +1,17 @@
|
||||
<%@ taglib uri = "http://java.sun.com/jsp/jstl/functions" prefix = "fn" %>
|
||||
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="${fn:substring(locale,0,2)}">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta charset="utf-8" />
|
||||
<base href="${requestScope['site.baseurl']}/static/webapp/">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
|
||||
<link rel="stylesheet" media="print" onload="this.onload=null;this.removeAttribute('media');" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap"/>
|
||||
|
||||
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap" as="style" onload="this.onload=null;this.rel='stylesheet'" crossorigin>
|
||||
<%@ include file="/jsp/pageHeaders.jsf" %>
|
||||
|
||||
<title>Loading | WiseMapping</title>
|
||||
<title>WiseMapping</title>
|
||||
|
||||
<script>
|
||||
window.serverconfig = {
|
||||
@ -20,7 +19,8 @@
|
||||
analyticsAccount: '${requestScope['google.analytics.account']}',
|
||||
clientType: 'rest',
|
||||
recaptcha2Enabled: ${requestScope['google.recaptcha2.enabled']},
|
||||
recaptcha2SiteKey: '${requestScope['google.recaptcha2.siteKey']}'
|
||||
recaptcha2SiteKey: '${requestScope['google.recaptcha2.siteKey']}',
|
||||
googleOauth2Url: '${requestScope['security.oauth2.google.url']}'
|
||||
};
|
||||
|
||||
</script>
|
||||
@ -34,7 +34,7 @@
|
||||
element.async = true;
|
||||
element.src = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js";
|
||||
document.body.appendChild(element);
|
||||
}, 2000);
|
||||
}, 50);
|
||||
};
|
||||
|
||||
window.addEventListener("load", downloadJsAtOnload, false);
|
||||
@ -46,8 +46,8 @@
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/webapp/vendors.bundle.js" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/webapp/app.bundle.js" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/webapp/vendors.bundle.js" crossorigin="anonymous" async></script>
|
||||
<script type="text/javascript" src="${requestScope['site.static.js.url']}/webapp/app.bundle.js" crossorigin="anonymous" async></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user