Start docker compoose.

This commit is contained in:
Paulo Gustavo Veiga
2024-02-03 23:10:32 -08:00
parent f046bcaebc
commit 71f77f6e79
192 changed files with 102 additions and 36 deletions

View File

@@ -0,0 +1,27 @@
package com.wisemapping;
import com.wisemapping.config.common.CommonConfig;
import com.wisemapping.config.mvc.MvcAppConfig;
import com.wisemapping.config.rest.RestAppConfig;
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).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,17 @@
package com.wisemapping.config.common;
import com.wisemapping.dao.LabelManagerImpl;
import com.wisemapping.security.AuthenticationProvider;
import com.wisemapping.service.MindmapServiceImpl;
import com.wisemapping.util.VelocityEngineUtils;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
@ComponentScan(basePackageClasses = {AuthenticationProvider.class, MindmapServiceImpl.class, LabelManagerImpl.class, VelocityEngineUtils.class})
@Import({JPAConfig.class, SecurityConfig.class})
@EnableAutoConfiguration
@ImportResource(value = {"classpath:spring/wisemapping-mail.xml"})
public class CommonConfig {
}

View File

@@ -0,0 +1,16 @@
package com.wisemapping.config.common;
import com.wisemapping.dao.MindmapManagerImpl;
import com.wisemapping.model.User;
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= User.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,43 @@
/*
* 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.config.mvc;
import com.wisemapping.filter.RequestPropertiesInterceptor;
import com.wisemapping.filter.UserLocaleInterceptor;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//@Configuration
//@ComponentScan(basePackageClasses = UserLocaleInterceptor.class)
public class InterceptorsConfig implements WebMvcConfigurer {
@Autowired
private UserLocaleInterceptor userLocaleInterceptor;
@Autowired
private RequestPropertiesInterceptor requestPropertiesInterceptor;
@Override
public void addInterceptors(@NotNull final InterceptorRegistry registry) {
registry.addInterceptor(userLocaleInterceptor);
registry.addInterceptor(requestPropertiesInterceptor);
}
}

View File

@@ -0,0 +1,49 @@
package com.wisemapping.config.mvc;
import com.wisemapping.webmvc.MvcMindmapController;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
//@SpringBootApplication
//@Import({MvcMindmapController.class, MvcSecurityConfig.class})
//@EnableWebMvc
public class MvcAppConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/**")
.addResourceLocations("classpath:/public/");
}
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
@Bean
HandlerExceptionResolver errorHandler() {
final SimpleMappingExceptionResolver result = new SimpleMappingExceptionResolver();
//mapping status code with view response.
result.addStatusCode("reactInclude", 403);
//setting default error view
result.setDefaultErrorView("reactInclude");
result.setDefaultStatusCode(500);
return result;
}
}

View File

@@ -0,0 +1,100 @@
package com.wisemapping.config.mvc;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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.web.SecurityFilterChain;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
@Configuration
@EnableWebSecurity
public class MvcSecurityConfig {
@Bean
@Order(1)
public SecurityFilterChain embeddedDisabledXOrigin(@NotNull final HttpSecurity http, @NotNull final MvcRequestMatcher.Builder mvc) throws Exception {
http
.securityMatchers((matchers) ->
matchers.requestMatchers(mvc.pattern("/c/maps/*/embed")))
.authorizeHttpRequests(
(auth) -> auth.requestMatchers(mvc.pattern(("/c/maps/*/embed"))).permitAll())
.headers((header -> header.frameOptions()
.disable()
))
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
@Bean
@Order(2)
public SecurityFilterChain mvcFilterChain(@NotNull final HttpSecurity http, @NotNull final MvcRequestMatcher.Builder mvc) throws Exception {
http
.securityMatchers((matchers) ->
matchers.requestMatchers(mvc.pattern("/c/**")))
.authorizeHttpRequests(
(auth) ->
auth
.requestMatchers(mvc.pattern("/c/login")).permitAll()
.requestMatchers(mvc.pattern("/c/logout")).permitAll()
.requestMatchers(mvc.pattern("/c/registration")).permitAll()
.requestMatchers(mvc.pattern("/c/registration-success")).permitAll()
.requestMatchers(mvc.pattern("/c/registration-google")).permitAll()
.requestMatchers(mvc.pattern("/c/forgot-password")).permitAll()
.requestMatchers(mvc.pattern("/c/forgot-password-success")).permitAll()
.requestMatchers(mvc.pattern("/c/maps/*/try")).permitAll()
.requestMatchers(mvc.pattern("/c/maps/*/public")).permitAll()
.requestMatchers(mvc.pattern("/c/**")).hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated())
.formLogin((loginForm) ->
loginForm.loginPage("/c/login")
.loginProcessingUrl("/c/perform-login")
.defaultSuccessUrl("/c/maps/")
.failureUrl("/c/login?login_error=2"))
.logout((logout) ->
logout
.logoutUrl("/c/logout")
.logoutSuccessUrl("/c/login")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll()
).rememberMe(remember ->
remember
.tokenValiditySeconds(2419200)
.rememberMeParameter("remember-me"
)
).headers((header -> header.frameOptions()
.disable()
))
.csrf((csrf) ->
csrf.ignoringRequestMatchers(mvc.pattern("/c/logout")));
return http.build();
}
@Bean
@Order(3)
public SecurityFilterChain shareResourcesFilterChain(@NotNull final HttpSecurity http, @NotNull final MvcRequestMatcher.Builder mvc) throws Exception {
return http.authorizeHttpRequests(
(auth) ->
auth.requestMatchers(mvc.pattern("/static/**")).permitAll().
requestMatchers(mvc.pattern("/css/**")).permitAll().
requestMatchers(mvc.pattern("/js/**")).permitAll().
// @todo: Why this is required ...
requestMatchers(mvc.pattern("/WEB-INF/jsp/*.jsp")).permitAll().
requestMatchers(mvc.pattern("/images/**")).permitAll().
requestMatchers(mvc.pattern("/*")).permitAll()
).build();
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.config.rest;
import com.wisemapping.filter.RequestPropertiesInterceptor;
import com.wisemapping.filter.UserLocaleInterceptor;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@ComponentScan(basePackageClasses = UserLocaleInterceptor.class)
public class InterceptorsConfig implements WebMvcConfigurer {
@Autowired
private UserLocaleInterceptor userLocaleInterceptor;
@Autowired
private RequestPropertiesInterceptor requestPropertiesInterceptor;
@Override
public void addInterceptors(@NotNull final InterceptorRegistry registry) {
registry.addInterceptor(userLocaleInterceptor);
registry.addInterceptor(requestPropertiesInterceptor);
}
}

View File

@@ -0,0 +1,51 @@
package com.wisemapping.config.rest;
import com.wisemapping.rest.MindmapController;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
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.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import static org.springframework.security.config.Customizer.withDefaults;
@SpringBootApplication(scanBasePackageClasses = MindmapController.class)
@Import({InterceptorsConfig.class})
@EnableWebSecurity
public class RestAppConfig {
@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 {
return http
.securityMatcher("/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers(mvc.pattern("/api/restfull/users/")).permitAll()
.requestMatchers(mvc.pattern("/api/restfull/users/resetPassword")).permitAll()
.requestMatchers(mvc.pattern("/api/restfull/oauth2/googlecallback")).permitAll()
.requestMatchers(mvc.pattern("/api/restfull/oauth2/confirmaccountsync")).permitAll()
.requestMatchers(mvc.pattern("/api/restfull/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))
.httpBasic(withDefaults())
.build();
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.config.rest;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ServletConfig implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
public void customize(ConfigurableServletWebServerFactory factory){
factory.setPort(8081);
}
}

View File

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

View File

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

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.dao;
import com.wisemapping.model.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface MindmapManager {
Collaborator findCollaborator(@NotNull String email);
List<Collaboration> findCollaboration(final int collaboratorId);
@Nullable
Mindmap getMindmapById(int mindmapId);
Mindmap getMindmapByTitle(final String name, final User user);
void addCollaborator(Collaborator collaborator);
void addMindmap(User user, Mindmap mindmap);
void saveMindmap(Mindmap mindmap);
void updateMindmap(@NotNull Mindmap mindmap, boolean saveHistory);
void removeCollaborator(@NotNull Collaborator collaborator);
void removeMindmap(Mindmap mindmap);
void removeCollaboration(Collaboration collaboration);
List<MindMapHistory> getHistoryFrom(int mindmapId);
MindMapHistory getHistory(int historyId);
void updateCollaboration(@NotNull Collaboration collaboration);
List<Mindmap> findMindmapByUser(User user);
}

View File

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

View File

@@ -0,0 +1,50 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.dao;
import com.wisemapping.model.AccessAuditory;
import com.wisemapping.model.Collaborator;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public interface UserManager {
List<User> getAllUsers();
User getUserBy(String email);
User getUserBy(int id);
void createUser(User user);
void auditLogin(@NotNull AccessAuditory accessAuditory);
void updateUser(User user);
User getUserByActivationCode(long code);
Collaborator getCollaboratorBy(String email);
User createUser(User user, Collaborator col);
void removeUser(@NotNull User user);
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.dao;
import com.wisemapping.model.*;
import com.wisemapping.security.DefaultPasswordEncoderFactories;
import com.wisemapping.security.LegacyPasswordEncoder;
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.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
@Repository
public class UserManagerImpl
implements UserManager {
@Autowired
private EntityManager entityManager;
@Autowired
private PasswordEncoder passwordEncoder;
public UserManagerImpl() {
}
public void setEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
public List<User> getAllUsers() {
return entityManager.createQuery("from com.wisemapping.model.User user", User.class).getResultList();
}
@Override
@Nullable
public User getUserBy(@NotNull final String email) {
User user = null;
TypedQuery<User> query = entityManager.createQuery("from com.wisemapping.model.User colaborator where email=:email", User.class);
query.setParameter("email", email);
final List<User> users = query.getResultList();
if (users != null && !users.isEmpty()) {
assert users.size() == 1 : "More than one user with the same email!";
user = users.get(0);
}
return user;
}
@Override
public Collaborator getCollaboratorBy(final String email) {
final Collaborator result;
final TypedQuery<Collaborator> query = entityManager.createQuery("from com.wisemapping.model.Collaborator colaborator where " +
"email=:email", Collaborator.class);
query.setParameter("email", email);
final List<Collaborator> cols = query.getResultList();
if (cols != null && !cols.isEmpty()) {
assert cols.size() == 1 : "More than one colaborator with the same email!";
result = cols.get(0);
} else {
result = null;
}
return result;
}
@Nullable
@Override
public User getUserBy(int id) {
return entityManager.find(User.class, id);
}
@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("");
}
entityManager.persist(user);
}
@Override
public User createUser(@NotNull User user, @NotNull Collaborator collaborator) {
assert user != null : "Trying to store a null user";
// Migrate from previous temporal collab to new user ...
collaborator.setEmail(collaborator.getEmail() + "_toRemove");
entityManager.merge(collaborator);
entityManager.flush();
// Save all new...
this.createUser(user);
// Update mindmap ...
final Set<Collaboration> collaborations = new CopyOnWriteArraySet<>(collaborator.getCollaborations());
for (Collaboration collabs : collaborations) {
collabs.setCollaborator(user);
}
// Delete old user ...
entityManager.remove(collaborator);
return user;
}
@Override
public void removeUser(@NotNull final User user) {
entityManager.remove(user);
}
public void auditLogin(@NotNull AccessAuditory accessAuditory) {
assert accessAuditory != null : "accessAuditory is null";
entityManager.persist(accessAuditory);
}
public void updateUser(@NotNull User user) {
assert user != null : "user is null";
// Does the password need to be encrypted ?
final String password = user.getPassword();
if (password != null && (!password.startsWith(LegacyPasswordEncoder.ENC_PREFIX) && !password.startsWith("{" + DefaultPasswordEncoderFactories.ENCODING_ID))) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
}
entityManager.merge(user);
}
public User getUserByActivationCode(long code) {
final User user;
final TypedQuery<User> query = entityManager.createQuery("from com.wisemapping.model.User user where " +
"activationCode=:activationCode", User.class);
query.setParameter("activationCode", code);
final List<User> users = query.getResultList();
if (users != null && !users.isEmpty()) {
assert users.size() == 1 : "More than one user with the same username!";
user = users.get(0);
} else {
user = null;
}
return user;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.exceptions;
import com.wisemapping.model.Collaborator;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
public class AccessDeniedSecurityException
extends ClientException {
public static final String MSG_KEY = "ACCESS_HAS_BEEN_REVOKED";
public AccessDeniedSecurityException(@NotNull String msg) {
super(msg, Severity.FATAL);
}
public AccessDeniedSecurityException(@NotNull long mapId, Collaborator user) {
super("No enough permissions to access map. Id: " + mapId + ", User: " + user, Severity.FATAL);
}
@NotNull
@Override
protected String getMsgBundleKey() {
return MSG_KEY;
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.exceptions;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.MessageSource;
import java.util.Locale;
abstract public class ClientException extends WiseMappingException {
private final Severity severity;
public ClientException(@NotNull String message, @NotNull Severity severity) {
super(message);
this.severity = severity;
}
protected abstract
@NotNull
String getMsgBundleKey();
public String getMessage(@NotNull final MessageSource messageSource, final @NotNull Locale locale) {
String message = messageSource.getMessage(this.getMsgBundleKey(), this.getMsgBundleArgs(), locale);
if(message==null){
message = this.getMessage();
}
return message;
}
protected Object[] getMsgBundleArgs(){
return null;
}
public Severity getSeverity() {
return this.severity;
}
public String getTechInfo() {
return getMessage();
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,56 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.exceptions;
import org.springframework.lang.Nullable;
import jakarta.validation.constraints.NotNull;
public class InvalidMindmapException
extends ClientException {
private static final String EMPTY_MINDMAP = "MINDMAP_EMPTY_ERROR";
private static final String INVALID_MINDMAP_FORMAT = "INVALID_MINDMAP_FORMAT";
private static final String TOO_BIG_MINDMAP = "TOO_BIG_MINDMAP";
private final String bundleKey;
private InvalidMindmapException(@NotNull String bundleKey, @Nullable String xmlDoc) {
super("Invalid mindmap format:" + xmlDoc, Severity.SEVERE);
this.bundleKey = bundleKey;
}
static public InvalidMindmapException emptyMindmap() {
return new InvalidMindmapException(EMPTY_MINDMAP, "<empty string>");
}
static public InvalidMindmapException invalidFormat(@Nullable String xmlDoc) {
return new InvalidMindmapException(INVALID_MINDMAP_FORMAT, xmlDoc);
}
static public InvalidMindmapException tooBigMindnap(int numberOfTopics) {
return new InvalidMindmapException(TOO_BIG_MINDMAP, "<too-big " + numberOfTopics + ">");
}
@NotNull
@Override
protected String getMsgBundleKey() {
return bundleKey;
}
}

View File

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

View File

@@ -0,0 +1,44 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.exceptions;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import com.wisemapping.service.LockManager;
import org.jetbrains.annotations.NotNull;
public class LockException
extends ClientException {
private static final String MSG_KEY = "MINDMAP_IS_LOCKED";
public LockException(@NotNull String message) {
super(message, Severity.INFO);
}
public static LockException createLockLost(@NotNull Mindmap mindmap, @NotNull User user, @NotNull LockManager manager) {
return new LockException("Lock can not be granted to " + user.getEmail() + ". The lock is assigned to " + manager.getLockInfo(mindmap));
}
@NotNull
@Override
protected String getMsgBundleKey() {
return MSG_KEY;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,44 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.exceptions;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
public class SessionExpiredException
extends ClientException {
private static final String MSG_KEY = "MINDMAP_TIMESTAMP_OUTDATED";
private final User lastUpdater;
public SessionExpiredException(@NotNull String debugInfo, @NotNull User lastUpdater) {
super(debugInfo, Severity.FATAL);
this.lastUpdater = lastUpdater;
}
@NotNull
@Override
protected String getMsgBundleKey() {
return MSG_KEY;
}
@Override
protected Object[] getMsgBundleArgs() {
return new String[]{lastUpdater.getFullName() + "<" + lastUpdater.getEmail() + ">"};
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.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() {
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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 org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Component
public class RequestPropertiesInterceptor implements HandlerInterceptor {
@Value("${google.analytics.enabled}")
private Boolean analyticsEnabled;
@Value("${google.analytics.account}")
private String analyticsAccount;
@Value("${google.recaptcha2.enabled}")
private Boolean recaptcha2Enabled;
@Value("${site.static.js.url}")
private String siteStaticUrl;
@Value("${google.recaptcha2.siteKey}")
private String recaptcha2SiteKey;
@Value("${google.ads.enabled}")
private Boolean adsEnabled;
@Value("${site.homepage}")
private String siteHomepage;
@Value("${site.baseurl:}")
private String siteUrl;
@Value("${security.oauth2.google.url}")
private String googleOauth2Url;
@Override
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, Object object) throws Exception {
request.setAttribute("google.analytics.enabled", analyticsEnabled);
request.setAttribute("google.analytics.account", analyticsAccount);
request.setAttribute("google.ads.enabled", adsEnabled);
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);
request.setAttribute("security.type", "db");
// If the property could not be resolved, try to infer one from the request...
if (siteUrl.isBlank()) {
siteUrl = request.getRequestURL().toString().replace(request.getRequestURI(), request.getContextPath());
}
request.setAttribute("site.baseurl", siteUrl);
return true;
}
}

View File

@@ -0,0 +1,23 @@
/*
* 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;
public interface SupportedUserAgent{
String USER_AGENT_HEADER = "User-Agent";
}

View File

@@ -0,0 +1,57 @@
/*
* 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 com.wisemapping.model.User;
import com.wisemapping.security.Utils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.util.Locale;
@Component
public class UserLocaleInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, Object object) throws Exception {
final HttpSession session = request.getSession(false);
User user = Utils.getUser(false);
if (user != null && session != null) {
String userLocale = user.getLocale();
final Locale sessionLocale = (Locale) session.getAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME);
if ((userLocale != null) && ((sessionLocale == null) || (!userLocale.equals(sessionLocale.toString())))) {
Locale locale;
if (userLocale.contains("_")) {
final String[] spit = userLocale.split("_");
locale = new Locale(spit[0], spit[1]);
} else {
locale = new Locale(userLocale);
}
session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
}
}
return true;
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.listener;
import com.wisemapping.exceptions.AccessDeniedSecurityException;
import com.wisemapping.exceptions.LockException;
import com.wisemapping.model.User;
import com.wisemapping.security.Utils;
import com.wisemapping.service.LockManager;
import com.wisemapping.service.MindmapService;
import org.jetbrains.annotations.NotNull;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
public class UnlockOnExpireListener implements HttpSessionListener {
private static final Logger logger = LogManager.getLogger();
@Override
public void sessionCreated(@NotNull HttpSessionEvent event) {
}
@Override
public void sessionDestroyed(@NotNull HttpSessionEvent event) {
final ServletContext servletContext = event.getSession().getServletContext();
final WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
final MindmapService mindmapService = (MindmapService) wc.getBean("mindmapService");
final LockManager lockManager = mindmapService.getLockManager();
final User user = Utils.getUser(false);
if (user != null) {
synchronized (mindmapService.getLockManager()) {
try {
lockManager.unlockAll(user);
} catch (LockException | AccessDeniedSecurityException e) {
logger.error(e);
}
}
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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;
import java.util.Calendar;
@Entity
@Table(name = "ACCESS_AUDITORY")
public class AccessAuditory
implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "login_Date")
private Calendar loginDate = null;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = true)
private User user = null;
public AccessAuditory() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setLoginDate(@NotNull Calendar loginDate) {
this.loginDate = loginDate;
}
public Calendar getLoginDate() {
return loginDate;
}
public void setUser(@NotNull User user) {
this.user = user;
}
public User getUser() {
return this.user;
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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;
public enum AuthenticationType {
DATABASE('D'),
LDAP('L'),
GOOGLE_OAUTH2('G');
private final char schemaCode;
AuthenticationType(char schemaCode) {
this.schemaCode = schemaCode;
}
public char getCode() {
return schemaCode;
}
@NotNull
public static AuthenticationType valueOf(char code) {
AuthenticationType result = null;
AuthenticationType[] values = AuthenticationType.values();
for (AuthenticationType value : values) {
if (value.getCode() == code) {
result = value;
break;
}
}
if (result == null) {
throw new IllegalStateException("Could not find auth with code:" + code);
}
return result;
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.model;
import org.jetbrains.annotations.Nullable;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Objects;
@Entity
@Table(name = "COLLABORATION")
public class Collaboration implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "role_id", unique = true)
private CollaborationRole role;
@ManyToOne
@JoinColumn(name = "mindmap_id", nullable = false)
private Mindmap mindMap;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "colaborator_id", nullable = false)
private Collaborator collaborator;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "properties_id", nullable = true, unique = true)
private CollaborationProperties collaborationProperties = new CollaborationProperties();
public Collaboration() {
}
public Collaboration(@NotNull CollaborationRole role, @NotNull Collaborator collaborator, @NotNull Mindmap mindmap) {
this.role = role;
this.mindMap = mindmap;
this.collaborator = collaborator;
// Guarantee referential integrity
mindmap.addCollaboration(this);
collaborator.addCollaboration(this);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getRoleId() {
return role.ordinal();
}
public void setRoleId(int roleId) {
this.role = CollaborationRole.values()[roleId];
}
public CollaborationRole getRole() {
return role;
}
public void setRole(@NotNull CollaborationRole role) {
this.role = role;
}
public Mindmap getMindMap() {
return mindMap;
}
public void setMindMap(Mindmap mindMap) {
this.mindMap = mindMap;
}
@NotNull
public Collaborator getCollaborator() {
return collaborator;
}
public void setCollaborator(@NotNull Collaborator collaborator) {
this.collaborator = collaborator;
}
@Nullable
public CollaborationProperties getCollaborationProperties() {
return this.collaborationProperties;
}
public void setCollaborationProperties(@Nullable CollaborationProperties collaborationProperties) {
this.collaborationProperties = collaborationProperties;
}
public boolean hasPermissions(@NotNull CollaborationRole role) {
return this.getRole().ordinal() <= role.ordinal();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Collaboration that = (Collaboration) o;
if (id != that.id) 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() {
//https://thorben-janssen.com/ultimate-guide-to-implementing-equals-and-hashcode-with-hibernate/
return 13;
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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;
public class CollaborationEmail
{
private String subject;
private String message;
public CollaborationEmail(){}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

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

View File

@@ -0,0 +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.model;
public enum CollaborationRole {
OWNER, EDITOR, VIEWER;
public String getLabel(){
return this.name().toLowerCase();
}
}

View File

@@ -0,0 +1,130 @@
/*
* 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.hibernate.annotations.CacheConcurrencyStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "COLLABORATOR")
@Inheritance(strategy = InheritanceType.JOINED)
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Collaborator implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String email;
@Column(name = "creation_date")
private Calendar creationDate;
@OneToMany(mappedBy = "collaborator")
private Set<Collaboration> collaborations = new HashSet<>();
public Collaborator() {
}
public Collaborator(Set<Collaboration> collaborations) {
this.collaborations = collaborations;
}
public void setCollaborations(Set<Collaboration> collaborations) {
this.collaborations = collaborations;
}
public void addCollaboration(@NotNull Collaboration collaboration) {
collaborations.add(collaboration);
}
public Set<Collaboration> getCollaborations() {
return collaborations;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Calendar getCreationDate() {
return creationDate;
}
public void setCreationDate(Calendar creationDate) {
this.creationDate = creationDate;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Collaborator that = (Collaborator) o;
if (id != that.getId()) return false;
return email != null ? email.equals(that.getEmail()) : that.getEmail() == null;
}
@Override
public int hashCode() {
int id = this.getId();
String email = this.getEmail();
int result = id ^ (id >>> 32);
result = 31 * result + (email != null ? email.hashCode() : 0);
return result;
}
public boolean identityEquality(@Nullable Collaborator that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (id != that.getId()) {
return false;
}
return email != null ? email.equals(that.getEmail()) : that.getEmail() == null;
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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;
public class Constants {
public static final int MAX_MAP_NAME_LENGTH = 512;
public static final int MAX_LABEL_NAME_LENGTH = 30;
public static final int MAX_MAP_DESCRIPTION_LENGTH = 512;
public static final int MAX_USER_LASTNAME_LENGTH = 255;
public static final int MAX_USER_FIRSTNAME_LENGTH = 255;
public static final int MAX_USER_PASSWORD_LENGTH = 255;
}

View File

@@ -0,0 +1,116 @@
/*
* 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.hibernate.annotations.CacheConcurrencyStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Objects;
@Entity
@Table(name = "LABEL")
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Label implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@NotNull
private String title;
@NotNull
private String color;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "creator_id", nullable = true, unique = true)
@NotNull
private User creator;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_label_id", nullable = true)
@Nullable
private Label parent;
public void setParent(@Nullable Label parent) {
this.parent = parent;
}
@Nullable
public Label getParent() {
return parent;
}
public void setCreator(@NotNull User creator) {
this.creator = creator;
}
@NotNull
public User getCreator() {
return creator;
}
@Nullable
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Nullable
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Label)) return false;
final Label label = (Label) o;
return id == label.id && creator.getId() == label.creator.getId()
&& Objects.equals(parent, label.parent);
}
@Override
public int hashCode() {
long result = title.hashCode();
result = 31 * result + (creator != null ? creator.hashCode() : 0);
result = 31 * result + (parent != null ? parent.hashCode() : 0);
return (int) result;
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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 java.util.ArrayList;
import java.util.List;
public class MindMapCriteria {
private String title;
private String description;
private boolean orConnector = false;
private int pageNro = 0;
public MindMapCriteria() {
}
public int getPageNro()
{
return pageNro;
}
public void setPageNro(int page)
{
this.pageNro = page;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void orCriteria() {
this.orConnector = true;
}
public void andCriteria() {
this.orConnector = false;
}
public boolean isOrCriteria() {
return this.orConnector;
}
public boolean isEmpty() {
return getTitle() != null || getDescription() != null;
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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 com.wisemapping.util.ZipUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import jakarta.persistence.*;
import java.io.IOException;
import java.util.Calendar;
@Entity
@Table(name = "MINDMAP_HISTORY")
public class MindMapHistory {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "creation_date")
private Calendar creationTime;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "editor_id", nullable = true,unique = false)
private User editor;
@Column(name = "xml")
private byte[] zippedXml;
@Column(name = "mindmap_id")
private int mindmapId;
public MindMapHistory() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getMindmapId() {
return mindmapId;
}
public void setMindmapId(int id) {
this.mindmapId = id;
}
@NotNull
public Calendar getCreationTime() {
return creationTime;
}
public void setCreationTime(Calendar creationTime) {
this.creationTime = creationTime;
}
@Nullable
public User getEditor() {
return editor;
}
public void setEditor(@Nullable User editor) {
this.editor = editor;
}
public byte[] getZippedXml() {
return zippedXml;
}
public void setZippedXml(byte[] value) {
zippedXml = value;
}
public byte[] getUnzipXml() throws IOException {
return ZipUtils.zipToBytes(getZippedXml());
}
}

View File

@@ -0,0 +1,365 @@
/*
* 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 com.wisemapping.exceptions.AccessDeniedSecurityException;
import com.wisemapping.exceptions.InvalidMindmapException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.util.ZipUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import jakarta.persistence.*;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.*;
@Entity
@Table(name = "MINDMAP")
public class Mindmap implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "creation_date")
private Calendar creationTime;
@Column(name = "edition_date")
private Calendar lastModificationTime;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "creator_id", unique = true)
private User creator;
@ManyToOne
@JoinColumn(name = "last_editor_id", nullable = false)
@NotFound(action = NotFoundAction.IGNORE)
private User lastEditor;
private String description;
@Column(name = "public")
private boolean isPublic;
@OneToMany(mappedBy = "mindMap", orphanRemoval = true, cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
private Set<Collaboration> collaborations = new HashSet<>();
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE})
@Fetch(FetchMode.JOIN)
@JoinTable(
name = "R_LABEL_MINDMAP",
joinColumns = @JoinColumn(name = "mindmap_id"),
inverseJoinColumns = @JoinColumn(name = "label_id"))
private Set<Label> labels = new LinkedHashSet<>();
private String title;
@Column(name = "xml")
@Basic(fetch = FetchType.LAZY)
private byte[] zippedXml;
public Mindmap() {
}
public void setUnzipXml(@NotNull byte[] value) {
try {
final byte[] zip = ZipUtils.bytesToZip(value);
this.setZippedXml(zip);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
public void setXmlStr(@NotNull String xml) throws InvalidMindmapException {
// Is a valid mindmap ... ?
MindmapUtils.verifyMindmap(xml);
this.setUnzipXml(xml.getBytes(StandardCharsets.UTF_8));
}
@NotNull
public byte[] getUnzipXml() {
byte[] result = new byte[]{};
if (zippedXml != null) {
try {
final byte[] zip = this.getZippedXml();
result = ZipUtils.zipToBytes(zip);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
return result;
}
@NotNull
public String getXmlStr() throws UnsupportedEncodingException {
return new String(this.getUnzipXml(), StandardCharsets.UTF_8);
}
@NotNull
public byte[] getZippedXml() {
return zippedXml;
}
public void setZippedXml(@NotNull byte[] value) {
this.zippedXml = value;
}
public Set<Collaboration> getCollaborations() {
return collaborations;
}
public void setCollaborations(Set<Collaboration> collaborations) {
this.collaborations = collaborations;
}
public void addCollaboration(@NotNull Collaboration collaboration) {
collaborations.add(collaboration);
}
public void removedCollaboration(@NotNull Collaboration collaboration) {
// https://stackoverflow.com/questions/25125210/hibernate-persistentset-remove-operation-not-working
this.collaborations.remove(collaboration);
collaboration.setMindMap(null);
}
public void removedCollaboration(@NotNull Set<Collaboration> collaborations) {
this.collaborations.removeAll(collaborations);
}
@NotNull
public Set<Label> getLabels() {
return labels;
}
public void setLabels(@NotNull final Set<Label> labels) {
this.labels = labels;
}
public void addLabel(@NotNull final Label label) {
this.labels.add(label);
}
public Optional<Collaboration> findCollaboration(@NotNull Collaborator collaborator) {
return this.collaborations
.stream()
.filter(c -> c.getCollaborator().identityEquality(collaborator))
.findAny();
}
@Nullable
public Collaboration findCollaboration(@NotNull String email) {
Collaboration result = null;
for (Collaboration collaboration : collaborations) {
if (collaboration.getCollaborator().getEmail().equals(email)) {
result = collaboration;
break;
}
}
return result;
}
public boolean isCreator(@NotNull User user) {
return this.getCreator() != null && this.getCreator().identityEquality(user);
}
public boolean isPublic() {
return isPublic;
}
public void setPublic(boolean isPublic) {
this.isPublic = isPublic;
}
public Calendar getLastModificationTime() {
return lastModificationTime;
}
public void setLastModificationTime(Calendar lastModificationTime) {
this.lastModificationTime = lastModificationTime;
}
@Nullable
public User getLastEditor() {
return lastEditor;
}
public void setLastEditor(@Nullable User lastEditor) {
this.lastEditor = lastEditor;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@NotNull
public String getXmlAsJsLiteral()
throws IOException {
String xml = this.getXmlStr();
xml = xml.replace("'", "\\'");
xml = xml.replace("\n", "\\n");
xml = xml.replace("\r", "");
xml = xml.replace("\\b", "\\\\b");
xml = xml.replace("\\t", "\\\\t");
xml = xml.replace("\\r", "\\\\r");
xml = xml.replace("\\f", "\\\\f");
xml = xml.trim();
return xml;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Calendar getCreationTime() {
return creationTime;
}
public void setCreationTime(Calendar creationTime) {
this.creationTime = creationTime;
}
public void setCreator(@NotNull User creator) {
this.creator = creator;
}
public User getCreator() {
return creator;
}
@Nullable
private CollaborationProperties findUserProperty(@NotNull Collaborator collaborator) {
final Optional<Collaboration> collaboration = this.findCollaboration(collaborator);
return collaboration.map(Collaboration::getCollaborationProperties).orElse(null);
}
public void setStarred(@NotNull Collaborator collaborator, boolean value) throws WiseMappingException {
final CollaborationProperties collaborationProperties = findCollaborationProperties(collaborator);
collaborationProperties.setStarred(value);
}
@NotNull
public CollaborationProperties findCollaborationProperties(@NotNull Collaborator collaborator) throws WiseMappingException {
return Objects.requireNonNull(this.findCollaborationProperties(collaborator, true));
}
@Nullable
public CollaborationProperties findCollaborationProperties(@NotNull Collaborator collaborator, boolean forceCheck) throws WiseMappingException {
if (collaborator == null) {
throw new IllegalStateException("Collaborator can not be null");
}
final Optional<Collaboration> collaboration = this.findCollaboration(collaborator);
CollaborationProperties result = null;
if (collaboration.isPresent()) {
result = collaboration.get().getCollaborationProperties();
} else {
if (forceCheck)
throw new AccessDeniedSecurityException("Collaborator " + collaborator.getEmail() + " could not access " + this.getId());
}
return result;
}
public boolean isStarred(@NotNull Collaborator collaborator) {
final CollaborationProperties collaboratorProperty = this.findUserProperty(collaborator);
return collaboratorProperty != null && collaboratorProperty.getStarred();
}
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();
}
static private String escapeXmlAttribute(String attValue) {
// Hack: Find out of the box function.
String result = attValue.replace("&", "&amp;");
result = result.replace("<", "&lt;");
result = result.replace("gt", "&gt;");
result = result.replace("\"", "&quot;");
return result;
}
public Mindmap shallowClone() {
final Mindmap result = new Mindmap();
result.setDescription(this.getDescription());
result.setTitle(this.getTitle());
result.setUnzipXml(this.getUnzipXml());
return result;
}
public boolean hasPermissions(@Nullable Collaborator collaborator, @NotNull CollaborationRole role) {
boolean result = false;
if (collaborator != null) {
final Optional<Collaboration> collaboration = this.findCollaboration(collaborator);
if (collaboration.isPresent()) {
result = collaboration.get().hasPermissions(role);
}
}
return result;
}
public boolean hasLabel(@NotNull final String name) {
for (Label label : this.labels) {
if (label.getTitle().equals(name)) {
return true;
}
}
return false;
}
public void removeLabel(@NotNull final Label label) {
this.labels.remove(label);
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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 com.wisemapping.exceptions.InvalidMindmapException;
import org.jetbrains.annotations.Nullable;
abstract public class MindmapUtils {
private static final int MAX_SUPPORTED_NODES = 4000;
public static void verifyMindmap(@Nullable String xmlDoc) throws InvalidMindmapException {
if (xmlDoc == null || xmlDoc.trim().isEmpty()) {
// Perform basic structure validation. Must have a map node and
throw InvalidMindmapException.emptyMindmap();
}
// Perform basic structure validation without parsing the XML.
if (!xmlDoc.trim().endsWith("</map>") || !xmlDoc.trim().startsWith("<map")) {
throw InvalidMindmapException.invalidFormat(xmlDoc);
}
int numberOfTopics = xmlDoc.split("<topic").length;
// Any valid map must contain at least a central topic ...
if (numberOfTopics == 0) {
throw InvalidMindmapException.invalidFormat(xmlDoc);
}
// Validate that the number of nodes is not bigger 5000 nodes.
if (numberOfTopics > MAX_SUPPORTED_NODES) {
throw InvalidMindmapException.tooBigMindnap(numberOfTopics);
}
}
}

View File

@@ -0,0 +1,197 @@
/*
* 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 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
extends Collaborator
implements Serializable {
public static final int MAX_PASSWORD_LENGTH_SIZE = 40;
private String firstname;
private String lastname;
private String password;
private String locale;
@Column(name = "activation_code")
private long activationCode;
@Column(name = "activation_date")
private Calendar activationDate;
@Column(name = "allow_send_email")
private boolean allowSendEmail = false;
@Column(name = "authentication_type")
private Character authenticationTypeCode = AuthenticationType.DATABASE.getCode();
@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() {
}
public String getFullName() {
return this.getFirstname() + " " + this.getLastname();
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getPassword() {
return password;
}
public void setPassword(@jakarta.validation.constraints.NotNull String password) {
this.password = password;
}
public boolean isActive() {
return activationDate != null;
}
public void setActivationCode(long code) {
this.activationCode = code;
}
public long getActivationCode() {
return activationCode;
}
public void setActivationDate(Calendar date) {
this.activationDate = date;
}
public Calendar getActivationDate() {
return activationDate;
}
public boolean isAllowSendEmail() {
return allowSendEmail;
}
public void setAllowSendEmail(boolean allowSendEmail) {
this.allowSendEmail = allowSendEmail;
}
@Nullable
public String getLocale() {
return locale;
}
public void setLocale(@Nullable String locale) {
this.locale = locale;
}
public char getAuthenticationTypeCode() {
return this.authenticationTypeCode;
}
public void setAuthenticationTypeCode(char code) {
this.authenticationTypeCode = code;
}
public AuthenticationType getAuthenticationType() {
return authenticationTypeCode != null ? AuthenticationType.valueOf(authenticationTypeCode) : AuthenticationType.DATABASE;
}
public void setAuthenticationType(@NotNull AuthenticationType authenticationType) {
this.authenticationTypeCode = authenticationType.getCode();
}
public boolean isDatabaseSchema() {
return this.getAuthenticationType() == AuthenticationType.DATABASE;
}
public String getAuthenticatorUri() {
return authenticatorUri;
}
public void setAuthenticatorUri(String authenticatorUri) {
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{" +
"firstname='" + firstname + '\'' +
", lastname='" + lastname + '\'' +
"', email = '" + this.getEmail() + "}";
}
}

View File

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

View File

@@ -0,0 +1,138 @@
/*
* 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.AuthenticationType;
import com.wisemapping.model.Collaboration;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
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.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
@RestController
@PreAuthorize("isAuthenticated() and hasRole('ROLE_ADMIN')")
public class AdminController extends BaseController {
@Qualifier("userService")
@Autowired
private UserService userService;
@Qualifier("mindmapService")
@Autowired
private MindmapService mindmapService;
@RequestMapping(method = RequestMethod.GET, value = "/api/restfull/admin/users/{id}", produces = {"application/json"})
@ResponseBody
public RestUser getUserById(@PathVariable int id) throws IOException {
final User userBy = userService.getUserBy(id);
if (userBy == null) {
throw new IllegalArgumentException("User could not be found");
}
return new RestUser(userBy);
}
@RequestMapping(method = RequestMethod.GET, value = "/api/restfull/admin/users/email/{email:.+}", produces = {"application/json"})
@ResponseBody
public RestUser getUserByEmail(@PathVariable String email) throws IOException {
final User 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 = "/api/restfull/admin/users", consumes = {"application/json"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.CREATED)
public void createUser(@RequestBody RestUser user, HttpServletResponse response) throws WiseMappingException {
if (user == null) {
throw new IllegalArgumentException("User could not be found");
}
// User already exists ?
final String email = user.getEmail();
if (userService.getUserBy(email) != null) {
throw new IllegalArgumentException("User already exists with this email.");
}
// Run some other validations ...
final User delegated = user.getDelegated();
final String lastname = delegated.getLastname();
if (lastname == null || lastname.isEmpty()) {
throw new IllegalArgumentException("lastname can not be null");
}
final String firstName = delegated.getFirstname();
if (firstName == null || firstName.isEmpty()) {
throw new IllegalArgumentException("firstname can not be null");
}
final String password = delegated.getPassword();
if (password == null || password.isEmpty()) {
throw new IllegalArgumentException("password can not be null");
}
// Finally create the user ...
delegated.setAuthenticationType(AuthenticationType.DATABASE);
userService.createUser(delegated, false, true);
response.setHeader("Location", "/api/restfull/admin/users/" + user.getId());
}
@RequestMapping(method = RequestMethod.PUT, value = "/api/restfull/admin/users/{id}/password", consumes = {"text/plain"})
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void changePassword(@RequestBody String password, @PathVariable int id) throws WiseMappingException {
if (password == null) {
throw new IllegalArgumentException("Password can not be null");
}
final User user = userService.getUserBy(id);
if (user == null) {
throw new IllegalArgumentException("User '" + id + "' could not be found");
}
user.setPassword(password);
userService.changePassword(user);
}
@RequestMapping(method = RequestMethod.DELETE, value = "/api/restfull/admin/users/{id}")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void deleteUserByEmail(@PathVariable int id) throws WiseMappingException {
final User user = userService.getUserBy(id);
if (user == null) {
throw new IllegalArgumentException("User '" + id + "' could not be found");
}
final List<Collaboration> collaborations = mindmapService.findCollaborations(user);
for (Collaboration collaboration : collaborations) {
final Mindmap mindmap = collaboration.getMindMap();
mindmapService.removeMindmap(mindmap, user);
}
userService.removeUser(user);
}
}

View File

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

View File

@@ -0,0 +1,26 @@
/*
* 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;
class JsonHttpMessageNotReadableException extends org.springframework.http.converter.HttpMessageNotReadableException {
public JsonHttpMessageNotReadableException(String msg, Exception cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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.LabelCouldNotFoundException;
import com.wisemapping.exceptions.ValidationException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.Label;
import com.wisemapping.model.User;
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 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;
@RestController
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
public class LabelController extends BaseController {
@Qualifier("labelService")
@Autowired
private LabelService labelService;
@RequestMapping(method = RequestMethod.POST, value = "/api/restfull/labels", 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.
if (title != null && !title.isEmpty()) {
restLabel.setTitle(title);
}
// Validate ...
validate(restLabel);
final Label label = createLabel(restLabel);
// Return the new created label ...
response.setHeader("Location", "/api/restfull/labels/" + label.getId());
response.setHeader("ResourceId", Long.toString(label.getId()));
}
@RequestMapping(method = RequestMethod.GET, value = "/api/restfull/labels/", produces = {"application/json"})
public RestLabelList retrieveList() {
final User user = Utils.getUser();
assert user != null;
final List<Label> all = labelService.getAll(user);
return new RestLabelList(all);
}
@RequestMapping(method = RequestMethod.DELETE, value = "/api/restfull/labels/{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);
if (label == null) {
throw new LabelCouldNotFoundException("Label could not be found. Id: " + id);
}
assert user != null;
labelService.removeLabel(label, user);
}
@NotNull private Label createLabel(@NotNull final RestLabel restLabel) throws WiseMappingException {
final Label label = restLabel.getDelegated();
// Add new label ...
final User user = Utils.getUser();
assert user != null;
labelService.addLabel(label, user);
return label;
}
private void validate(@NotNull final RestLabel restLabel) throws ValidationException {
final BindingResult result = new BeanPropertyBindingResult(restLabel, "");
new LabelValidator(labelService).validate(restLabel.getDelegated(), result);
if (result.hasErrors()) {
throw new ValidationException(result);
}
}
}

View File

@@ -0,0 +1,669 @@
/*
* 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.*;
import com.wisemapping.model.*;
import com.wisemapping.rest.model.*;
import com.wisemapping.security.Utils;
import com.wisemapping.service.*;
import com.wisemapping.validator.MapInfoValidator;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.validator.routines.EmailValidator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
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 java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
@RestController
@Transactional(propagation = Propagation.REQUIRED)
public class MindmapController extends BaseController {
private final Logger logger = LogManager.getLogger();
private static final String LATEST_HISTORY_REVISION = "latest";
@Qualifier("mindmapService")
@Autowired
private MindmapService mindmapService;
@Qualifier("labelService")
@Autowired
private LabelService labelService;
@Qualifier("userService")
@Autowired
private UserService userService;
@Value("${accounts.maxInactive:20}")
private int maxAccountsInactive;
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/api/restfull/maps/{id}", produces = {"application/json"})
@ResponseBody
public RestMindmap retrieve(@PathVariable int id) throws WiseMappingException {
final User user = Utils.getUser();
final Mindmap mindMap = findMindmapById(id);
return new RestMindmap(mindMap, user);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/api/restfull/maps/", produces = {"application/json"})
public RestMindmapList retrieveList(@RequestParam(required = false) String q) {
final User user = Utils.getUser();
final MindmapFilter filter = MindmapFilter.parse(q);
List<Mindmap> mindmaps = mindmapService.findMindmapsByUser(user);
mindmaps = mindmaps
.stream()
.filter(m -> filter.accept(m, user)).toList();
return new RestMindmapList(mindmaps, user);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/api/restfull/maps/{id}/history/", produces = {"application/json"})
public RestMindmapHistoryList fetchHistory(@PathVariable int id) {
final List<MindMapHistory> histories = mindmapService.findMindmapHistory(id);
final RestMindmapHistoryList result = new RestMindmapHistoryList();
for (MindMapHistory history : histories) {
result.addHistory(new RestMindmapHistory(history));
}
return result;
}
@RequestMapping(method = RequestMethod.PUT, value = "/api/restfull/maps/{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();
// Validate arguments ...
final String properties = restMindmap.getProperties();
if (properties == null) {
throw new IllegalArgumentException("Map properties can not be null");
}
// Have permissions ?
final LockManager lockManager = mindmapService.getLockManager();
lockManager.lock(mindmap, user);
// Update collaboration properties ...
final CollaborationProperties collaborationProperties = mindmap.findCollaborationProperties(user);
collaborationProperties.setMindmapProperties(properties);
// Validate content ...
final String xml = restMindmap.getXml();
mindmap.setXmlStr(xml);
// Update map ...
saveMindmapDocument(minor, mindmap, user);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(value = "/api/restfull/maps/{id}/history/{hid}", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updateRevertMindmap(@PathVariable int id, @PathVariable String hid) throws WiseMappingException, IOException {
final Mindmap mindmap = findMindmapById(id);
final User user = Utils.getUser();
if (LATEST_HISTORY_REVISION.equals(hid)) {
// Revert to the latest stored version ...
List<MindMapHistory> mindmapHistory = mindmapService.findMindmapHistory(id);
if (mindmapHistory.size() > 0) {
final MindMapHistory mindMapHistory = mindmapHistory.get(0);
mindmap.setZippedXml(mindMapHistory.getZippedXml());
saveMindmapDocument(true, mindmap, user);
}
} else {
mindmapService.revertChange(mindmap, Integer.parseInt(hid));
}
}
@PreAuthorize("permitAll()")
@RequestMapping(method = RequestMethod.GET, value = {"/api/restfull/maps/{id}/document/xml", "/api/restfull/maps/{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);
String xmlStr = mindmap.getXmlStr();
return xmlStr.getBytes(StandardCharsets.UTF_8);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = {"/api/restfull/maps/{id}/document/xml"}, consumes = {"text/plain"})
@ResponseBody
public void updateDocument(@PathVariable int id, @RequestBody String xmlDoc) throws WiseMappingException, IOException {
final Mindmap mindmap = findMindmapById(id);
final User user = Utils.getUser();
mindmap.setXmlStr(xmlDoc);
saveMindmapDocument(false, mindmap, user);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = {"/api/restfull/maps/{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 = "/api/restfull/maps/{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 String xml = restMindmap.getXml();
if (xml != null && !xml.isEmpty()) {
mindmap.setXmlStr(xml);
}
// Update title ...
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");
}
mindmap.setTitle(title);
}
// Update description ...
final String description = restMindmap.getDescription();
if (description != null) {
mindmap.setDescription(description);
}
// Update document properties ...
final String properties = restMindmap.getProperties();
if (properties != null) {
final CollaborationProperties collaborationProperties = mindmap.findCollaborationProperties(user);
collaborationProperties.setMindmapProperties(properties);
}
// Update map ...
saveMindmapDocument(minor, mindmap, user);
}
@NotNull
private Mindmap findMindmapById(int id) throws MapCouldNotFoundException, AccessDeniedSecurityException {
// Has enough permissions ?
final User user = Utils.getUser();
if (!mindmapService.hasPermissions(user, id, CollaborationRole.VIEWER)) {
throw new AccessDeniedSecurityException(id, user);
}
// Does the map exists ?
final Mindmap result = mindmapService.findMindmapById(id);
if (result == null) {
throw new MapCouldNotFoundException("Map could not be found. Id:" + id);
}
return result;
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/api/restfull/maps/{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();
// 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");
}
// Update map ...
final Mindmap mindmap = findMindmapById(id);
mindmap.setTitle(title);
mindmapService.updateMindmap(mindMap, false);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/api/restfull/maps/{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();
if (!mindMap.hasPermissions(user, CollaborationRole.OWNER)) {
throw new IllegalArgumentException("No enough permissions");
}
// Do not allow more than 20 collabs not active
verifyActiveCollabs(restCollabs, user);
// Compare one by one if some of the elements has been changed ....
final Set<Collaboration> collabsToRemove = new HashSet<>(mindMap.getCollaborations());
for (RestCollaboration restCollab : restCollabs.getCollaborations()) {
final String email = restCollab.getEmail();
// Is a valid email address ?
if (!EmailValidator.getInstance().isValid(email)) {
throw new InvalidEmailException(email);
}
final Collaboration collaboration = mindMap.findCollaboration(email);
// Validate role format ...
String roleStr = restCollab.getRole();
if (roleStr == null) {
throw new IllegalArgumentException(roleStr + " is not a valid role");
}
// Remove from the list of pending to remove ...
if (collaboration != null) {
collabsToRemove.remove(collaboration);
}
// Is owner ?
final CollaborationRole role = CollaborationRole.valueOf(roleStr.toUpperCase());
if (role != CollaborationRole.OWNER) {
mindmapService.addCollaboration(mindMap, restCollab.getEmail(), role, restCollabs.getMessage());
}
}
// Remove all collaborations that no applies anymore ..
for (final Collaboration collaboration : collabsToRemove) {
mindmapService.removeCollaboration(mindMap, collaboration);
}
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/api/restfull/maps/{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();
if (!mindMap.hasPermissions(user, CollaborationRole.OWNER)) {
throw new AccessDeniedSecurityException("User must be owner to share mindmap");
}
// Do not allow more than 20 collabs not active
verifyActiveCollabs(restCollabs, user);
// Is valid email address ?
final EmailValidator emailValidator = EmailValidator.getInstance();
final Set<String> invalidEmails = restCollabs
.getCollaborations()
.stream()
.map(RestCollaboration::getEmail)
.filter(e -> !emailValidator.isValid(e)).collect(Collectors.toSet());
if (!invalidEmails.isEmpty()) {
throw new InvalidEmailException(String.join(", ", invalidEmails));
}
// Has any role changed ?. Just removed it.
final Map<String, Collaboration> collabByEmail = mindMap
.getCollaborations()
.stream()
.collect(Collectors.toMap(collaboration -> collaboration.getCollaborator().getEmail(), collaboration -> collaboration));
// Great, let's add all the collabs again ...
for (RestCollaboration restCollab : restCollabs.getCollaborations()) {
// Validate newRole format ...
final String roleStr = restCollab.getRole();
if (roleStr == null) {
throw new IllegalArgumentException(roleStr + " is not a valid newRole");
}
// Had the newRole changed ?. Otherwise, don't touch it.
final CollaborationRole newRole = CollaborationRole.valueOf(roleStr.toUpperCase());
final String collabEmail = restCollab.getEmail();
final Collaboration currentCollab = collabByEmail.get(collabEmail);
if (currentCollab == null || currentCollab.getRole() != newRole) {
// Are we trying to change the owner ...
if (currentCollab != null && currentCollab.getRole() == CollaborationRole.OWNER) {
throw new OwnerCannotChangeException(collabEmail);
}
// Role can not be changed ...
if (newRole == CollaborationRole.OWNER) {
throw new OwnerCannotChangeException(collabEmail);
}
// This is collaboration that with different newRole, try to change it ...
if (currentCollab != null) {
mindmapService.removeCollaboration(mindMap, currentCollab);
}
mindmapService.addCollaboration(mindMap, collabEmail, newRole, restCollabs.getMessage());
}
}
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/api/restfull/maps/{id}/collabs", produces = {"application/json"})
public RestCollaborationList retrieveList(@PathVariable int id) throws MapCouldNotFoundException, AccessDeniedSecurityException {
final Mindmap mindMap = findMindmapById(id);
final Set<Collaboration> collaborations = mindMap.getCollaborations();
final List<RestCollaboration> collabs = new ArrayList<>();
for (Collaboration collaboration : collaborations) {
collabs.add(new RestCollaboration(collaboration));
}
final RestCollaborationList result = new RestCollaborationList();
result.setCollaborations(collabs);
return result;
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/api/restfull/maps/{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);
mindmap.setDescription(description);
mindmapService.updateMindmap(mindmap, false);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/api/restfull/maps/{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();
if (!mindMap.hasPermissions(user, CollaborationRole.OWNER)) {
throw new IllegalArgumentException("No enough to execute this operation");
}
// Update map status ...
mindMap.setPublic(Boolean.parseBoolean(value));
mindmapService.updateMindmap(mindMap, false);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/api/restfull/maps/{id}")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void deleteMapById(@PathVariable int id) throws IOException, WiseMappingException {
final User user = Utils.getUser();
final Mindmap mindmap = findMindmapById(id);
mindmapService.removeMindmap(mindmap, user);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/api/restfull/maps/{id}/collabs")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void deleteCollabByEmail(@PathVariable int id, @RequestParam(required = false) String email) throws IOException, WiseMappingException {
logger.debug("Deleting permission for email:" + email);
// Is a valid email address ?
final EmailValidator emailValidator = EmailValidator.getInstance();
if (!emailValidator.isValid(email)) {
throw new InvalidEmailException(email);
}
final Mindmap mindmap = findMindmapById(id);
final User user = Utils.getUser();
// Only owner can change collaborators...
if (!mindmap.hasPermissions(user, CollaborationRole.OWNER)) {
throw new IllegalArgumentException("No enough permissions");
}
final Collaboration collab = mindmap.findCollaboration(email);
if (collab != null) {
CollaborationRole role = collab.getRole();
// Owner collab can not be removed ...
if (role == CollaborationRole.OWNER) {
throw new IllegalArgumentException("Can not remove owner collab");
}
mindmapService.removeCollaboration(mindmap, collab);
}
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/api/restfull/maps/{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();
// Update map status ...
final boolean starred = Boolean.parseBoolean(value);
final Optional<Collaboration> collaboration = mindmap.findCollaboration(user);
if (!collaboration.isPresent()) {
throw new WiseMappingException("No enough permissions.");
}
collaboration.get().getCollaborationProperties().setStarred(starred);
mindmapService.updateCollaboration(user, collaboration.get());
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.GET, value = "/api/restfull/maps/{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 Optional<Collaboration> collaboration = mindmap.findCollaboration(user);
if (!collaboration.isPresent()) {
throw new WiseMappingException("No enough permissions.");
}
boolean result = collaboration.get().getCollaborationProperties().getStarred();
return Boolean.toString(result);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/api/restfull/maps/batch")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void batchDelete(@RequestParam() String ids) throws IOException, WiseMappingException {
final User user = Utils.getUser();
final String[] mapsIds = ids.split(",");
try {
for (final String mapId : mapsIds) {
final Mindmap mindmap = findMindmapById(Integer.parseInt(mapId));
mindmapService.removeMindmap(mindmap, user);
}
} catch (Exception e) {
final AccessDeniedSecurityException accessDenied = new AccessDeniedSecurityException("Map could not be deleted. Maps to be deleted:" + ids);
accessDenied.initCause(e);
throw accessDenied;
}
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/api/restfull/maps", 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 {
final Mindmap mindmap = new Mindmap();
if (title != null && !title.isEmpty()) {
mindmap.setTitle(title);
}
if (description != null && !description.isEmpty()) {
mindmap.setDescription(description);
}
// Validate ...
final BindingResult result = new BeanPropertyBindingResult(mindmap, "");
new MapInfoValidator(mindmapService).validate(mindmap, result);
if (result.hasErrors()) {
throw new ValidationException(result);
}
// If the user has not specified the xml content, add one ...
if (mapXml == null || mapXml.isEmpty()) {
mapXml = Mindmap.getDefaultMindmapXml(mindmap.getTitle());
}
mindmap.setXmlStr(mapXml);
// Add new mindmap ...
final User user = Utils.getUser(true);
mindmapService.addMindmap(mindmap, user);
// Return the new created map ...
response.setHeader("Location", "/api/restfull/maps/" + mindmap.getId());
response.setHeader("ResourceId", Integer.toString(mindmap.getId()));
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/api/restfull/maps/{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 {
// Validate ...
final BindingResult result = new BeanPropertyBindingResult(restMindmap, "");
new MapInfoValidator(mindmapService).validate(restMindmap.getDelegated(), result);
if (result.hasErrors()) {
throw new ValidationException(result);
}
// Some basic validations ...
final User user = Utils.getUser();
// Create a shallowCopy of the map ...
final Mindmap mindMap = findMindmapById(id);
final Mindmap clonedMap = mindMap.shallowClone();
clonedMap.setTitle(restMindmap.getTitle());
clonedMap.setDescription(restMindmap.getDescription());
// Add new mindmap ...
mindmapService.addMindmap(clonedMap, user);
// Return the new created map ...
response.setHeader("Location", "/api/restfull/maps/" + clonedMap.getId());
response.setHeader("ResourceId", Integer.toString(clonedMap.getId()));
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.DELETE, value = "/api/restfull/maps/{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 Mindmap mindmap = findMindmapById(id);
final Label label = labelService.findLabelById(lid, user);
if (label == null) {
throw new LabelCouldNotFoundException("Label could not be found. Id: " + lid);
}
mindmap.removeLabel(label);
mindmapService.updateMindmap(mindmap, false);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.POST, value = "/api/restfull/maps/{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);
if (label == null) {
throw new LabelCouldNotFoundException("Label could not be found. Id: " + lid);
}
final Mindmap mindmap = findMindmapById(id);
mindmap.addLabel(label);
mindmapService.updateMindmap(mindmap, false);
}
@PreAuthorize("isAuthenticated() and hasRole('ROLE_USER')")
@RequestMapping(method = RequestMethod.PUT, value = "/api/restfull/maps/{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 LockManager lockManager = mindmapService.getLockManager();
final Mindmap mindmap = findMindmapById(id);
ResponseEntity<RestLockInfo> result = new ResponseEntity<>(null, HttpStatus.NO_CONTENT);
if (Boolean.parseBoolean(value)) {
final LockInfo lockInfo = lockManager.lock(mindmap, user);
final RestLockInfo restLockInfo = new RestLockInfo(lockInfo, user);
result = new ResponseEntity<>(restLockInfo, HttpStatus.OK);
} else {
lockManager.unlock(mindmap, user);
}
return result;
}
private void saveMindmapDocument(boolean minor, @NotNull final Mindmap mindMap, @NotNull final User user) throws WiseMappingException {
final Calendar now = Calendar.getInstance();
mindMap.setLastModificationTime(now);
mindMap.setLastEditor(user);
mindmapService.updateMindmap(mindMap, !minor);
}
private ValidationException buildValidationException(@NotNull String fieldName, @NotNull String message) throws WiseMappingException {
final BindingResult result = new BeanPropertyBindingResult(new RestMindmap(), "");
result.rejectValue(fieldName, "error.not-specified", null, message);
return new ValidationException(result);
}
private void verifyActiveCollabs(@NotNull RestCollaborationList restCollabs, User user) throws TooManyInactiveAccountsExceptions {
// Do not allow more than 20 new accounts per mindmap...
final List<Mindmap> userMindmaps = mindmapService.findMindmapsByUser(user);
final Set<String> allEmails = userMindmaps
.stream()
.filter(m -> m.hasPermissions(user, CollaborationRole.OWNER))
.map(Mindmap::getCollaborations)
.flatMap(Collection::stream)
.map(c -> c.getCollaborator().getEmail())
.collect(Collectors.toSet());
allEmails.addAll(restCollabs
.getCollaborations().stream()
.map(RestCollaboration::getEmail)
.collect(Collectors.toSet()));
long inactiveAccounts = allEmails.stream().filter(e -> userService.getUserBy(e) == null).count();
if (inactiveAccounts > maxAccountsInactive) {
throw new TooManyInactiveAccountsExceptions(inactiveAccounts);
}
}
}

View File

@@ -0,0 +1,105 @@
/*
* 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.model.Mindmap;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class MindmapFilter {
public static final MindmapFilter ALL = new MindmapFilter("all") {
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
return true;
}
};
public static final MindmapFilter MY_MAPS = new MindmapFilter("my_maps") {
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
return mindmap.getCreator().identityEquality(user);
}
};
public static final MindmapFilter STARRED = new MindmapFilter("starred") {
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User 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) {
return !MY_MAPS.accept(mindmap, user);
}
};
public static final MindmapFilter PUBLIC = new MindmapFilter("public") {
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
return mindmap.isPublic();
}
};
protected String id;
private static final MindmapFilter[] values = {ALL, MY_MAPS, PUBLIC, STARRED, SHARED_WITH_ME};
private MindmapFilter(@NotNull String id) {
this.id = id;
}
static public MindmapFilter parse(@Nullable final String valueStr) {
MindmapFilter result = null;
if (valueStr != null) {
for (MindmapFilter value : MindmapFilter.values) {
if (value.id.equals(valueStr)) {
result = value;
break;
}
}
// valueStr is not a default filter
if (result == null) {
result = new LabelFilter(valueStr);
}
} else {
result = ALL;
}
return result;
}
abstract boolean accept(@NotNull Mindmap mindmap, @NotNull User user);
private static final class LabelFilter extends MindmapFilter {
private LabelFilter(@NotNull String id) {
super(id);
}
@Override
boolean accept(@NotNull Mindmap mindmap, @NotNull User user) {
return mindmap.hasLabel(this.id);
}
}
}

View File

@@ -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 jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
@RestController
@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()) {
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);
}
}

View File

@@ -0,0 +1,150 @@
/*
* 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.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.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.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.stereotype.Controller;
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
@CrossOrigin
public class UserController extends BaseController {
@Qualifier("userService")
@Autowired
private UserService userService;
@Autowired
private RecaptchaService captchaService;
@Qualifier("authenticationManager")
@Autowired
private AuthenticationManager authManager;
@Value("${google.recaptcha2.enabled:false}")
private Boolean recatchaEnabled;
@Value("${accounts.exclusion.domain:''}")
private String domainBanExclusion;
private static final Logger logger = LogManager.getLogger();
private static final String REAL_IP_ADDRESS_HEADER = "X-Real-IP";
@RequestMapping(method = RequestMethod.POST, value = "/users/", produces = { "application/json" })
@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 (registration.getPassword().length() > User.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 User user = new User();
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", "/service/users/" + user.getId());
}
@RequestMapping(method = RequestMethod.PUT, value = "/users/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 (recatchaEnabled) {
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,72 @@
/*
* 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.wisemapping.model.Collaboration;
import com.wisemapping.model.CollaborationRole;
import org.jetbrains.annotations.NotNull;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
public class RestCollaboration {
private int id;
private String email;
private String role;
public RestCollaboration(@NotNull Collaboration collaboration) {
this.id = collaboration.getId();
this.email = collaboration.getCollaborator().getEmail();
this.role = collaboration.getRole().getLabel();
}
public RestCollaboration() {
}
public void setRole(@NotNull final String value) {
if (value == null) {
throw new IllegalStateException("role can not be null");
}
// Only check ...
CollaborationRole.valueOf(value.toUpperCase());
role = value;
}
public int getId() {
return id;
}
public String getRole() {
return role;
}
public String getEmail() {
return email;
}
public void setEmail(@NotNull String email) {
this.email = email;
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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 org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
public class RestCollaborationList {
private List<RestCollaboration> collaborations;
private String message;
public RestCollaborationList() {
collaborations = new ArrayList<RestCollaboration>();
}
public int getCount() {
return this.collaborations.size();
}
public void setCount(int count) {
}
public List<RestCollaboration> getCollaborations() {
return collaborations;
}
public void addCollaboration(@NotNull RestCollaboration collaboration) {
collaborations.add(collaboration);
}
public void setCollaborations(@NotNull List<RestCollaboration> collaborations) {
this.collaborations = collaborations;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -0,0 +1,64 @@
/*
* 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.wisemapping.model.Collaborator;
import com.wisemapping.util.TimeUtils;
import org.jetbrains.annotations.NotNull;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import java.util.Calendar;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
public class RestCollaborator {
@JsonIgnore
private final Collaborator collaborator;
public RestCollaborator(@NotNull Collaborator collaborator) {
this.collaborator = collaborator;
}
public String getCreationDate() {
return TimeUtils.toISO8601(collaborator.getCreationDate().getTime());
}
public void setCreationDate(Calendar creationDate) {
}
public String getEmail() {
return collaborator.getEmail();
}
public void setEmail(String email) {
}
}

View File

@@ -0,0 +1,148 @@
/*
* 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.exceptions.Severity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
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(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY
)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestErrors {
@JsonIgnore
private Errors errors;
@JsonIgnore
private List<String> gErrors;
@JsonIgnore
MessageSource messageSource;
@JsonIgnore
Severity gSeverity;
@Nullable
@JsonIgnore
private String _debugInfo;
public RestErrors() {
}
public RestErrors(@NotNull Errors errors, @NotNull MessageSource messageSource) {
this.errors = errors;
this.messageSource = messageSource;
this.gErrors = this.processGlobalErrors(errors);
this.gSeverity = Severity.WARNING;
}
public RestErrors(@NotNull String errorMsg, @NotNull Severity severity) {
this(errorMsg, severity, null);
}
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;
}
private List<String> processGlobalErrors(@NotNull Errors errors) {
final List<String> result = new ArrayList<>();
final List<ObjectError> globalErrors = errors.getGlobalErrors();
for (ObjectError globalError : globalErrors) {
result.add(globalError.getObjectName());
}
return result;
}
public void setGlobalErrors(List<String> list) {
// Implemented only for XML serialization contract ...
}
public Map<String, String> getFieldErrors() {
Locale locale = LocaleContextHolder.getLocale();
final Map<String, String> result = new HashMap<>();
if (errors != null) {
final List<FieldError> fieldErrors = errors.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
result.put(fieldError.getField(), messageSource.getMessage(fieldError, locale));
}
}
return result;
}
public void setFieldErrors(Map<String, String> fieldErrors) {
// Implemented only for XML serialization contract ...
}
public void setGlobalSeverity(@NotNull String severity) {
// Implemented only for XML serialization contract ...
}
public void setDebugInfo(@Nullable String debugInfo) {
// Implemented only for XML serialization contract ...
}
@Nullable
public String getGlobalSeverity() {
return this.gSeverity.toString();
}
@Nullable
public String getDebugInfo() {
return _debugInfo;
}
public List<String> getGlobalErrors() {
return gErrors;
}
@Override
public String toString() {
return "RestErrors{" +
"errors=" + errors +
", gErrors=" + gErrors +
", messageSource=" + messageSource +
", gSeverity=" + gSeverity +
", _debugInfo='" + _debugInfo + '\'' +
'}';
}
}

View File

@@ -0,0 +1,71 @@
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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY;
@JsonAutoDetect(
fieldVisibility = NONE,
setterVisibility = PUBLIC_ONLY,
isGetterVisibility = NONE,
getterVisibility = PUBLIC_ONLY
)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestLabel {
@JsonIgnore
private final Label label;
public RestLabel() {
this(new Label());
}
public RestLabel(@NotNull final Label label) {
this.label = label;
}
public void setParent(final Label parent) {
this.label.setParent(parent);
}
@Nullable
public Label getParent() {
return this.label.getParent();
}
@Nullable
public String getTitle() {
return this.label.getTitle();
}
public int getId() {
return label.getId();
}
public void setId(int id) {
label.setId(id);
}
public void setTitle(String title) {
label.setTitle(title);
}
public void setColor(final String color) {
label.setColor(color);
}
@Nullable public String getColor() {
return label.getColor();
}
@JsonIgnore
public Label getDelegated() {
return label;
}
}

View File

@@ -0,0 +1,35 @@
package com.wisemapping.rest.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.wisemapping.model.Label;
import org.jetbrains.annotations.NotNull;
import jakarta.xml.bind.annotation.XmlElement;
import java.util.ArrayList;
import java.util.List;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
public class RestLabelList {
@NotNull private final List<RestLabel> restLabels;
public RestLabelList(){
this.restLabels = new ArrayList<>();
}
public RestLabelList(@NotNull final List<Label> labels) {
this.restLabels = new ArrayList<>(labels.size());
for (Label label : labels) {
this.restLabels.add(new RestLabel(label));
}
}
@NotNull @XmlElement(name = "label")
public List<RestLabel> getLabels() {
return restLabels;
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.wisemapping.model.User;
import com.wisemapping.service.LockInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestLockInfo {
private String email;
// This is required only for compliance with the JAXB serializer.
public RestLockInfo() {
}
public RestLockInfo(@Nullable LockInfo lockInfo, @NotNull User user) {
this.email = user.getEmail();
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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 org.jetbrains.annotations.NotNull;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
public class RestLogItem {
private String jsStack;
private String userAgent;
private String jsErrorMsg;
public int getMapId() {
return mapId;
}
public void setMapId(int mapId) {
this.mapId = mapId;
}
private int mapId;
public String getJsStack() {
return jsStack;
}
public void setJsStack(@NotNull String jsStack) {
this.jsStack = jsStack;
}
public String getUserAgent() {
return userAgent;
}
public void setUserAgent(String userAgent) {
this.userAgent = userAgent;
}
public String getJsErrorMsg() {
return jsErrorMsg;
}
public void setJsErrorMsg(String jsErrorMsg) {
this.jsErrorMsg = jsErrorMsg;
}
}

View File

@@ -0,0 +1,193 @@
/*
* 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.exceptions.InvalidMindmapException;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.*;
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;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY
)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestMindmap {
@JsonIgnore
private final Collaborator collaborator;
@JsonIgnore
private final Mindmap mindmap;
@Nullable
private String properties;
public RestMindmap() throws WiseMappingException {
this(new Mindmap(), null);
}
public RestMindmap(@NotNull Mindmap mindmap, @Nullable Collaborator collaborator) throws WiseMappingException {
this.mindmap = mindmap;
this.collaborator = collaborator;
if (collaborator != null) {
final CollaborationProperties collaborationProperties = mindmap.findCollaborationProperties(collaborator, false);
if (collaborationProperties != null) {
this.properties = collaborationProperties.getMindmapProperties();
}
}
}
public void setCreationTime(final String creationTime) {
// Ignore
}
public String getCreationTime() {
final Calendar creationTime = mindmap.getCreationTime();
String result = null;
if (creationTime != null) {
result = TimeUtils.toISO8601(creationTime.getTime());
}
return result;
}
public String getDescription() {
return mindmap.getDescription();
}
public void setDescription(String description) {
mindmap.setDescription(description);
}
public String getTitle() {
return mindmap.getTitle();
}
public void setTitle(String title) {
mindmap.setTitle(title);
}
public int getId() {
return mindmap.getId();
}
public void setId(int id) {
mindmap.setId(id);
}
public String getCreator() {
final User creator = mindmap.getCreator();
return creator != null ? creator.getEmail() : null;
}
public void setCreator(String creatorUser) {
}
public RestCollaborator getLastModifierUser() {
final User lastEditor = mindmap.getLastEditor();
RestCollaborator result = null;
if (lastEditor != null && mindmap.hasPermissions(collaborator, CollaborationRole.EDITOR)) {
result = new RestCollaborator(lastEditor);
}
return result;
}
public void setLastModifierUser(RestUser lastModifierUser) {
}
public String getLastModificationTime() {
final Calendar date = mindmap.getLastModificationTime();
String result = null;
if (date != null) {
result = TimeUtils.toISO8601(date.getTime());
}
return result;
}
public void setLastModificationTime(final String value) {
}
public boolean isPublic() {
return mindmap.isPublic();
}
public void setPublic(boolean value) {
// return mindmap.isPublic();
}
public String getXml() throws IOException {
return mindmap.getXmlStr();
}
public void setXml(@Nullable String xml) throws IOException, InvalidMindmapException {
if (xml != null) {
mindmap.setXmlStr(xml);
}
}
public String getOwner() {
final User owner = mindmap.getCreator();
return owner != null ? owner.getEmail() : null;
}
public void setOwner(String owner) {
}
@Nullable
public String getProperties() {
return properties;
}
public void setProperties(@Nullable String properties) {
this.properties = properties;
}
public boolean getStarred() {
boolean result = false;
if (collaborator != null) {
result = mindmap.isStarred(collaborator);
}
return result;
}
public void setStarred(boolean value) throws WiseMappingException {
if (collaborator != null) {
mindmap.setStarred(collaborator, value);
}
}
@JsonIgnore
public Mindmap getDelegated() {
return this.mindmap;
}
}

View File

@@ -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.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.wisemapping.model.MindMapHistory;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY
)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestMindmapHistory {
static private final SimpleDateFormat sdf;
private int id;
private Calendar creation;
private String creator;
static {
sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public RestMindmapHistory() {
}
public RestMindmapHistory(@NotNull MindMapHistory history) {
this.id = history.getId();
this.creation = history.getCreationTime();
final User editor = history.getEditor();
this.creator = editor != null ? editor.getFullName() : "";
}
public String getCreationTime() {
return this.toISO8601(creation.getTime());
}
public void setCreationTime() {
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
}
public void setId(int id) {
this.id=id;
}
private String toISO8601(@NotNull Date date) {
return sdf.format(date) + "Z";
}
public int getId() {
return id;
}
}

View File

@@ -0,0 +1,55 @@
/**
* 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 org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
public class RestMindmapHistoryList {
private final List<RestMindmapHistory> changes;
public RestMindmapHistoryList() {
changes = new ArrayList<RestMindmapHistory>();
}
public int getCount() {
return this.changes.size();
}
public void setCount(int count) {
}
public List<RestMindmapHistory> getChanges() {
return changes;
}
public void addHistory(@NotNull RestMindmapHistory history) {
changes.add(history);
}
}

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.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.wisemapping.model.*;
import com.wisemapping.security.Utils;
import com.wisemapping.util.TimeUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Calendar;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY
)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestMindmapInfo {
public static final String ROLE_NONE = "none";
@JsonIgnore
private final Mindmap mindmap;
@JsonIgnore
private Set<RestLabel> restLabels;
@JsonIgnore
private int mapId = -1;
private final Collaborator collaborator;
public RestMindmapInfo() {
this(new Mindmap(), null);
}
public RestMindmapInfo(@NotNull Mindmap mindmap, @Nullable Collaborator collaborator) {
this.mindmap = mindmap;
this.collaborator = collaborator;
}
public void setCreationTime(String value) {
// Ignore
}
public String getCreationTime() {
final Calendar creationTime = mindmap.getCreationTime();
return creationTime != null ? TimeUtils.toISO8601(creationTime.getTime()) : null;
}
public String getDescription() {
return mindmap.getDescription();
}
public void setDescription(String description) {
mindmap.setDescription(description);
}
public String getTitle() {
return mindmap.getTitle();
}
public void setTitle(String title) {
mindmap.setTitle(title);
}
public Set<RestLabel> getLabels() {
// Support test deserialization...
Set<RestLabel> result = this.restLabels;
if (result == null) {
final User me = Utils.getUser();
result = mindmap.getLabels().
stream()
.filter(l -> l.getCreator().equals(me))
.map(RestLabel::new)
.collect(Collectors.toSet());
}
return result;
}
public void setLabels(Set<RestLabel> restLabels) {
this.restLabels = restLabels;
}
public int getId() {
int result = this.mapId;
if (mapId == -1) {
result = mindmap.getId();
}
return result;
}
public void setId(int id) {
this.mapId = id;
}
public String getCreator() {
final User creator = mindmap.getCreator();
return creator != null ? creator.getFullName() : null;
}
public void setCreator(String email) {
}
public void setCreator() {
// Do nothing ...
}
public String getRole() {
final User user = Utils.getUser();
String result;
final Optional<Collaboration> collaboration = mindmap.findCollaboration(user);
return collaboration.map(value -> value.getRole().getLabel()).orElse(ROLE_NONE);
}
public void setRole(String value) {
// Do nothing ...
}
public String getLastModifierUser() {
final User user = mindmap.getLastEditor();
return user != null ? user.getFullName() : "unknown";
}
public void setLastModifierUser(String value) {
}
public String getLastModificationTime() {
final Calendar calendar = mindmap.getLastModificationTime();
return calendar != null ? TimeUtils.toISO8601(calendar.getTime()) : null;
}
public void setLastModificationTime(String value) {
}
public boolean getPublic() {
return mindmap.isPublic();
}
public boolean getStarred() {
return mindmap.isStarred(collaborator);
}
public void setStarred(boolean value) {
}
@JsonIgnore
public Mindmap getDelegated() {
return this.mindmap;
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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.wisemapping.model.Collaborator;
import com.wisemapping.model.Mindmap;
import org.jetbrains.annotations.NotNull;
import jakarta.xml.bind.annotation.XmlElement;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
public class RestMindmapList {
private List<RestMindmapInfo> mindmapsInfo;
public RestMindmapList() {
this(Collections.emptyList(), null);
}
public RestMindmapList(@NotNull List<Mindmap> mindmaps, Collaborator collaborator) {
this.mindmapsInfo = mindmaps.stream()
.map(m->new RestMindmapInfo(m, collaborator))
.collect(Collectors.toList());
}
public int getCount() {
return this.mindmapsInfo.size();
}
public void setCount(int count) {
}
@XmlElement(name = "map")
public List<RestMindmapInfo> getMindmapsInfo() {
return mindmapsInfo;
}
public void setMindmapsInfo(List<RestMindmapInfo> mindmapsInfo) {
this.mindmapsInfo = mindmapsInfo;
}
}

View File

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

View File

@@ -0,0 +1,7 @@
package com.wisemapping.rest.model;
public enum RestResetPasswordAction {
EMAIL_SENT, OAUTH2_USER
}

View File

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

View File

@@ -0,0 +1,126 @@
/*
* 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.fasterxml.jackson.annotation.JsonInclude;
import com.wisemapping.model.AuthenticationType;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
@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 RestUser {
private final User user;
private String password;
public RestUser() {
this(new User());
}
public RestUser(@NotNull User user) {
this.user = user;
}
public Calendar getCreationDate() {
return user.getCreationDate();
}
public String getLocale() {
return user.getLocale();
}
public String getFirstname() {
return user.getFirstname();
}
public void setFirstname(String firstname) {
user.setFirstname(firstname);
}
public String getLastname() {
return user.getLastname();
}
public void setLastname(String lastname) {
user.setLastname(lastname);
}
public int getId() {
return user.getId();
}
public void setId(int id) {
user.setId(id);
}
public String getEmail() {
return user.getEmail();
}
public void setEmail(String email) {
user.setEmail(email);
}
public void setPassword(final String password) {
this.user.setPassword(password);
this.password = password;
}
public String getPassword() {
return password;
}
@JsonIgnore
public User getDelegated() {
return this.user;
}
public AuthenticationType getAuthenticationType() {
return user.getAuthenticationType();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof RestUser)) {
return false;
}
RestUser restUser = (RestUser) o;
return this.getDelegated().identityEquality(restUser.getDelegated());
}
@Override
public int hashCode() {
return this.getDelegated().hashCode();
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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.User;
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
@JsonIgnoreProperties(ignoreUnknown = true)
public class RestUserRegistration {
private String email;
private String firstname;
private String lastname;
private String password;
private String recaptcha;
@JsonIgnore
public User build() {
final User user = new User();
user.setFirstname(firstname);
user.setLastname(lastname);
user.setEmail(email);
user.setPassword(password);
return user;
}
public String getEmail() {
return email;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
public String getPassword() {
return password;
}
public String getRecaptcha() {
return recaptcha;
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
public class AuthenticationProvider implements org.springframework.security.authentication.AuthenticationProvider {
private UserDetailsService userDetailsService;
private PasswordEncoder encoder;
@Override()
public Authentication authenticate(@NotNull final Authentication auth) throws AuthenticationException {
// All your user authentication needs
final String email = auth.getName();
final UserDetails userDetails = getUserDetailsService().loadUserByUsername(email);
final User user = userDetails.getUser();
final String credentials = (String) auth.getCredentials();
if (user == null || credentials == null || !encoder.matches(user.getPassword(), credentials)) {
throw new BadCredentialsException("Username/Password does not match for " + auth.getPrincipal());
}
// User has been disabled ...
if (!user.isActive()) {
throw new BadCredentialsException("User has been disabled for login " + auth.getPrincipal());
}
userDetailsService.getUserService().auditLogin(user);
return new UsernamePasswordAuthenticationToken(userDetails, credentials, userDetails.getAuthorities());
}
@Override
public boolean supports(final Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
public void setEncoder(@NotNull PasswordEncoder encoder) {
this.encoder = encoder;
}
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.HashMap;
import java.util.Map;
public class DefaultPasswordEncoderFactories {
public static final String ENCODING_ID = "bcrypt";
public static PasswordEncoder createDelegatingPasswordEncoder() {
final Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put(ENCODING_ID, new BCryptPasswordEncoder(12));
DelegatingPasswordEncoder result = new DelegatingPasswordEncoder(ENCODING_ID, encoders);
result.setDefaultPasswordEncoderForMatches(new LegacyPasswordEncoder());
return result;
}
}

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.User;
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 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);
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import org.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;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class LegacyPasswordEncoder implements PasswordEncoder {
final private static Logger logger = LogManager.getLogger();
public static final String ENC_PREFIX = "ENC:";
private final ShaPasswordEncoder sha1Encoder = new ShaPasswordEncoder();
@Override
public String encode(CharSequence rawPassword) {
logger.debug("LegacyPasswordEncoder encode executed.");
return ENC_PREFIX + sha1Encoder.encode(rawPassword.toString(), "");
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
final String encode = encode(rawPassword);
return encode.equals(encodedPassword);
}
}
/**
* Just copied to keep compatibility with Spring 3.
*/
class ShaPasswordEncoder {
private final String algorithm;
private final boolean encodeHashAsBase64;
/**
* The digest algorithm to use
* Supports the named <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html#AppA">
* Message Digest Algorithms</a> in the Java environment.
**/
ShaPasswordEncoder() {
this("SHA-1", false);
}
/**
* Convenience constructor for specifying the algorithm and whether or not to enable base64 encoding
*
* @param algorithm
* @param encodeHashAsBase64
* @throws IllegalArgumentException if an unknown
*/
private ShaPasswordEncoder(String algorithm, boolean encodeHashAsBase64) throws IllegalArgumentException {
this.algorithm = algorithm;
this.encodeHashAsBase64 = encodeHashAsBase64;
getMessageDigest();
}
/**
* Encodes the rawPass using a MessageDigest.
* If a salt is specified it will be merged with the password before encoding.
*
* @param rawPass The plain text password
* @param salt The salt to sprinkle
* @return Hex string of password digest (or base64 encoded string if encodeHashAsBase64 is enabled.
*/
public String encode(String rawPass, Object salt) {
String saltedPass = mergePasswordAndSalt(rawPass, salt, false);
MessageDigest messageDigest = getMessageDigest();
byte[] digest = messageDigest.digest(Utf8.encode(saltedPass));
if (getEncodeHashAsBase64()) {
return Utf8.decode(Base64.encode(digest));
} else {
return new String(Hex.encode(digest));
}
}
/**
* Get a MessageDigest instance for the given algorithm.
* Throws an IllegalArgumentException if <i>algorithm</i> is unknown
*
* @return MessageDigest instance
* @throws IllegalArgumentException if NoSuchAlgorithmException is thrown
*/
private final MessageDigest getMessageDigest() throws IllegalArgumentException {
try {
return MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException("No such algorithm [" + algorithm + "]");
}
}
//~ Methods ========================================================================================================
private boolean getEncodeHashAsBase64() {
return encodeHashAsBase64;
}
private String mergePasswordAndSalt(String password, Object salt, boolean strict) {
if (password == null) {
password = "";
}
if (strict && (salt != null)) {
if ((salt.toString().lastIndexOf("{") != -1)
|| (salt.toString().lastIndexOf("}") != -1)) {
throw new IllegalArgumentException("Cannot use { or } in salt.toString()");
}
}
if ((salt == null) || "".equals(salt)) {
return password;
} else {
return password + "{" + salt.toString() + "}";
}
}
}

View File

@@ -0,0 +1,6 @@
package com.wisemapping.security;
public enum MapAccessPermission {
READ,
WRITE
}

View File

@@ -0,0 +1,91 @@
package com.wisemapping.security;
import com.wisemapping.model.Collaborator;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import jakarta.validation.constraints.NotNull;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import java.io.Serializable;
public class MapAccessPermissionEvaluation implements PermissionEvaluator {
final private static Logger logger = LogManager.getLogger();
private MapPermissionsSecurityAdvice readAdvice;
private MapPermissionsSecurityAdvice updateAdvice;
public MapAccessPermissionEvaluation(final @NotNull MapPermissionsSecurityAdvice readAdvice, final @NotNull MapPermissionsSecurityAdvice updateAdvice) {
this.readAdvice = readAdvice;
this.updateAdvice = updateAdvice;
}
@Override
public boolean hasPermission(
@NotNull Authentication auth, @NotNull Object targetDomainObject, @NotNull Object permission) {
logger.log(Level.DEBUG, "auth: " + auth + ",targetDomainObject:" + targetDomainObject + ",permission:" + permission);
if ((auth == null) || (targetDomainObject == null) || !(permission instanceof String)) {
logger.debug("Permissions could not be validated, illegal parameters.");
return false;
}
boolean result;
final User user = Utils.getUser();
final MapAccessPermission perm = MapAccessPermission.valueOf((permission.toString().toUpperCase()));
if (targetDomainObject instanceof Integer) {
// Checking permissions by mapId ...
final int mapId = (Integer) targetDomainObject;
result = hasPrivilege(mapId, perm);
} else if (targetDomainObject instanceof Mindmap) {
final Mindmap map = (Mindmap) targetDomainObject;
result = hasPrivilege(map, perm);
} else if (targetDomainObject instanceof Collaborator collab) {
// Read only operations checks ...
result = user.identityEquality(collab) || readAdvice.getMindmapService().isAdmin(user);
} else {
throw new IllegalArgumentException("Unsupported check control of permissions");
}
if (!result) {
logger.debug("User '" + (user != null ? user.getEmail() : "none") + "' not allowed to invoke");
}
return result;
}
@Override
public boolean hasPermission(
@NotNull Authentication auth, Serializable targetId, @NotNull String targetType, @NotNull Object
permission) {
logger.log(Level.FATAL, "Unsupported privilege: auth: " + auth + ",targetId:" + targetType + ",targetType:" + targetType + ", permission:" + permission);
return false;
}
private boolean hasPrivilege(@NotNull int mapId, @NotNull MapAccessPermission permission) {
boolean result;
final User user = Utils.getUser();
if (MapAccessPermission.READ == permission) {
result = readAdvice.isAllowed(user, mapId);
} else {
result = updateAdvice.isAllowed(user, mapId);
}
return result;
}
private boolean hasPrivilege(@NotNull Mindmap map, @NotNull MapAccessPermission permission) {
boolean result;
final User user = Utils.getUser();
if (MapAccessPermission.READ == permission) {
result = readAdvice.isAllowed(user, map);
} else {
result = updateAdvice.isAllowed(user, map);
}
return result;
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import com.wisemapping.service.MindmapService;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class MapPermissionsSecurityAdvice {
@Autowired private MindmapService mindmapService;
protected abstract boolean isAllowed(@Nullable User user, Mindmap map);
protected abstract boolean isAllowed(@Nullable User user, int mapId);
protected MindmapService getMindmapService() {
return mindmapService;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import com.wisemapping.model.CollaborationRole;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Component;
@Component
public class ReadSecurityAdvise
extends MapPermissionsSecurityAdvice {
protected boolean isAllowed(@Nullable User user, Mindmap map) {
return getMindmapService().hasPermissions(user, map, CollaborationRole.VIEWER);
}
protected boolean isAllowed(@Nullable User user, int mapId) {
return getMindmapService().hasPermissions(user, mapId, CollaborationRole.VIEWER);
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import com.wisemapping.model.CollaborationRole;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Component;
@Component
public class UpdateSecurityAdvise
extends MapPermissionsSecurityAdvice {
@Override
protected boolean isAllowed(@Nullable User user, @NotNull Mindmap map) {
boolean result;
if (map.getCreator() == null) {
// This means that the map is new and is an add operation.
result = true;
} else {
result = getMindmapService().hasPermissions(user, map, CollaborationRole.EDITOR);
}
return result;
}
@Override
protected boolean isAllowed(@Nullable User user, int mapId) {
return getMindmapService().hasPermissions(user, mapId, CollaborationRole.EDITOR);
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.ArrayList;
import java.util.Collection;
public class UserDetails implements org.springframework.security.core.userdetails.UserDetails {
private final com.wisemapping.model.User user;
private final boolean isAdmin;
public UserDetails(@NotNull final com.wisemapping.model.User user, boolean isAdmin) {
this.user = user;
this.isAdmin = isAdmin;
}
public Collection<? extends GrantedAuthority> getAuthorities() {
final Collection<GrantedAuthority> result = new ArrayList<GrantedAuthority>();
if (this.isAdmin) {
final SimpleGrantedAuthority role_admin = new SimpleGrantedAuthority("ROLE_ADMIN");
result.add(role_admin);
}
final SimpleGrantedAuthority role_user = new SimpleGrantedAuthority("ROLE_USER");
result.add(role_user);
return result;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return this.user.isActive();
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return this.user.isActive();
}
public User getUser() {
return user;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import 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.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class UserDetailsService
implements org.springframework.security.core.userdetails.UserDetailsService {
@Autowired
private UserService userService;
@Value("${admin.user}")
private String adminUser;
@Override
public UserDetails loadUserByUsername(@NotNull String email) throws UsernameNotFoundException, DataAccessException {
final User user = userService.getUserBy(email);
if (user != null) {
return new UserDetails(user, isAdmin(email));
} else {
throw new UsernameNotFoundException(email);
}
}
private boolean isAdmin(@Nullable String email) {
return email != null && adminUser != null && email.trim().endsWith(adminUser);
}
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userManager) {
this.userService = userManager;
}
public String getAdminUser() {
return adminUser;
}
public void setAdminUser(String adminUser) {
this.adminUser = adminUser;
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright [2022] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wisemapping.security;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
final public class Utils {
private Utils() {
}
@SuppressWarnings({"ConstantConditions"})
@Nullable
public static User getUser() {
return getUser(false);
}
@NotNull
public static User getUser(boolean forceCheck) {
User result = null;
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getDetails() != null)
{
final Object principal = auth.getPrincipal();
if (principal != null && principal instanceof UserDetails) {
result = ((UserDetails)principal).getUser();
}
}
if(result==null && forceCheck){
throw new IllegalStateException("User could not be retrieved");
}
return result;
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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.service;
import com.wisemapping.exceptions.WiseMappingException;
public class CollaborationException
extends WiseMappingException
{
public CollaborationException(String msg)
{
super(msg);
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.service;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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.service;
import com.wisemapping.exceptions.WiseMappingException;
public class InvalidActivationCodeException
extends WiseMappingException
{
public InvalidActivationCodeException(String msg)
{
super(msg);
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.service;
import com.wisemapping.exceptions.WiseMappingException;
public class InvalidAuthSchemaException extends WiseMappingException
{
public InvalidAuthSchemaException(String msg)
{
super(msg);
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.service;
import com.wisemapping.exceptions.WiseMappingException;
public class InvalidUserEmailException extends WiseMappingException
{
public InvalidUserEmailException(String msg)
{
super(msg);
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.service;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.Label;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface LabelService {
void addLabel(@NotNull final Label label, @NotNull final User user) throws WiseMappingException;
@NotNull List<Label> getAll(@NotNull final User user);
@Nullable
Label findLabelById(int id, @NotNull final User user);
Label getLabelByTitle(@NotNull String title, @NotNull final User user);
void removeLabel(@NotNull final Label label, @NotNull final User user) throws WiseMappingException;
}

View File

@@ -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.service;
import com.wisemapping.dao.LabelManager;
import com.wisemapping.exceptions.WiseMappingException;
import com.wisemapping.model.Label;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service("labelService")
@Transactional(propagation = Propagation.REQUIRED)
public class LabelServiceImpl implements LabelService {
@Autowired
private LabelManager labelManager;
@Override
@PreAuthorize("hasAnyRole('USER', 'ADMIN') && hasPermission(#user, 'WRITE')")
public void addLabel(@NotNull final Label label, @NotNull final User user) {
label.setCreator(user);
labelManager.addLabel(label);
}
@NotNull
@Override
@PreAuthorize("hasAnyRole('USER', 'ADMIN') && hasPermission(#user, 'READ')")
public List<Label> getAll(@NotNull final User user) {
return labelManager.getAllLabels(user);
}
@Override
@PreAuthorize("hasAnyRole('USER', 'ADMIN') && hasPermission(#user, 'READ')")
public Label findLabelById(int id, @NotNull final User user) {
return labelManager.getLabelById(id, user);
}
@Nullable
@Override
@PreAuthorize("hasAnyRole('USER', 'ADMIN') && hasPermission(#user, 'READ')")
public Label getLabelByTitle(@NotNull String title, @NotNull final User user) {
return labelManager.getLabelByTitle(title, user);
}
@Override
@PreAuthorize("hasAnyRole('USER', 'ADMIN') && hasPermission(#user, 'WRITE')")
public void removeLabel(@NotNull Label label, @NotNull User user) throws WiseMappingException {
if (label.getCreator().equals(user)) {
labelManager.removeLabel(label);
} else {
throw new WiseMappingException("User: "+ user.getFullName() + "has no ownership on label " + label.getTitle());
}
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.service;
import com.wisemapping.model.Mindmap;
import com.wisemapping.model.User;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
public class LockInfo {
final private User user;
private Calendar timeout;
private static final int EXPIRATION_MIN = 30;
public int getMapId() {
return mapId;
}
public void setMapId(int mapId) {
this.mapId = mapId;
}
private int mapId;
public LockInfo(@NotNull User user, @NotNull Mindmap mindmap) {
this.user = user;
this.mapId = mindmap.getId();
this.updateTimeout();
}
public User getUser() {
return user;
}
public boolean isExpired() {
return timeout.before(Calendar.getInstance());
}
public void updateTimeout() {
final Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, EXPIRATION_MIN);
this.timeout = calendar;
}
@Override
public String toString() {
return "LockInfo{" +
"user=" + user +
", timeout=" + timeout +
", mapId=" + mapId +
'}';
}
}

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