diff --git a/README.md b/README.md index 799ffe51..3ab8d10f 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,17 @@ In order to reduce the life-cycle to develop UI backend testing, you can do the A quick and dirty solution to share changes in the UI is to manually compile the dist. This will make the loader file available without the need to publish: -`yarn --cwd wisemapping-frontend build;cp -r wisemapping-frontend/packages/mindplot/dist/* wisemapping-open-source/wise-ui/target/wisemapping-mindplot/package/dist;cp -r wisemapping-frontend/packages/mindplot/dist/* wisemapping-open-source/wise-ui/target/wisemapping-mindplot/package/dist` +`yarn --cwd wisemapping-frontend build;cp -r wisemapping-frontend/packages/mindplot/dist/* wisemapping-open-source/wise-ui/target/wisemapping-mindplot/package/dist;cp -r wisemapping-frontend/packages/webapp/dist/* wisemapping-open-source/wise-ui/target/wisemapping-webapp/package/dist` ### Compiling and running with docker-compose -Check out the [docker section](./docker/README. +Check out the [docker section](./docker/README.) + +### Test reports + +Individual test result reports can be found in wisemapping-open-source/wise-webapp/target/failsafe-reports/index.html +Test coverage report of unit and integration test can be found in wisemapping-open-source/wise-webapp/target/site/jacoco and wisemapping-open-source/wise-webapp/target/site/jacoco-it folders. Coverage report is generated in the verify phase of [lifecicle](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#introduction-to-the-build-lifecyclea) using [jacoco](https://www.jacoco.org/jacoco/trunk/doc/maven.html) ## Members @@ -60,13 +65,10 @@ Check out the [docker section](./docker/README. * Paulo Veiga * Pablo Luna -### Individual Contributors - - * Ezequiel Bergamaschi - ### Past Individual Contributors - * Ignacio Manzano + * Ignacio Manzano + * Ezequiel Bergamaschi ## License diff --git a/distribution/README.md b/distribution/README.md index 32908080..fe858c97 100644 --- a/distribution/README.md +++ b/distribution/README.md @@ -9,15 +9,27 @@ There are multiple ways to run WiseMapping depending on your database configurat ## Option 1: Running HSQL within the image storage -> $ docker run -it --rm -p 8080:8080 veigap/wisemapping:latest> +> $ docker run -it --rm -p 8080:8080 wisemapping/wisemapping:latest -Then, open your browser at `http://localhost:8888`. A default user is available for testing `test@wisemapping.com` and password `test`. +Then, open your browser at `http://localhost:8888`. A default user is available for testing `test@wisemapping.org` and password `test`. ***This option, all changes will be lost once the image is stopped. Use it for testing only*** ## Option 2: Running HSQL with mounted directory -> $ docker run -it --rm -p 8080:8080 veigap/wisemapping:latest +Only one time, copy the empty default out of the container: + +> $ mkdir your- db-dir-store-path +> +> $ docker run --name wiseapp -d --mount type=bind,source=your-db-dir-store-path,target=/var/lib/wise-db wisemapping/wisemapping:latest +> +> $ docker cp wiseapp:/var/lib/wisemapping/db your-db-dir-store-path +> +> $ docker stop wiseapp;docker rm wiseapp + +Then, execute the container mounting tbe directory: + +> $ docker run --mount type=bind,source=your-db-dir-store-path/db,target=/var/lib/wisemapping/db -it --rm -p 8080:8080 wisemapping/wisemapping:latest ## Option 3: External MySQL/PostgreSQL @@ -36,7 +48,7 @@ Download `app.properties` configuration file and configure the required sections Run the application mounting your previously configured `app.properties` -> $ docker run --mount type=bind,source=your-file-path/app.properties,target=/usr/local/tomcat/webapps/ROOT/WEB-INF/app.properties -it --rm -p 8080:8080 veigap/wisemapping:latest +> $ docker run --mount type=bind,source=your-file-path/app.properties,target=/usr/local/tomcat/webapps/ROOT/WEB-INF/app.properties -it --rm -p 8080:8080 wisemapping/wisemapping:latest # Advanced configuration diff --git a/pom.xml b/pom.xml index 2e655ed3..e7c4cee3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> - 5.0.11 + 5.0.12 ${project.basedir}/wise-webapps @@ -16,7 +16,7 @@ org.wisemapping wisemapping WiseMapping Project - 5.0.11 + 5.0.12 pom diff --git a/wise-ui/pom.xml b/wise-ui/pom.xml index e0899ebf..d2bbb19c 100644 --- a/wise-ui/pom.xml +++ b/wise-ui/pom.xml @@ -12,7 +12,7 @@ org.wisemapping wisemapping ../pom.xml - 5.0.11 + 5.0.12 @@ -29,11 +29,11 @@ - + - + @@ -42,11 +42,11 @@ - + - + diff --git a/wise-webapp/pom.xml b/wise-webapp/pom.xml index a7b30423..c8799a2c 100644 --- a/wise-webapp/pom.xml +++ b/wise-webapp/pom.xml @@ -1,5 +1,4 @@ - + 4.0.0 wise-webapp war @@ -9,13 +8,13 @@ org.wisemapping wisemapping ../pom.xml - 5.0.11 + 5.0.12 - 5.3.18 + 5.3.22 5.6.2 - 5.6.5.Final + 5.6.11.Final 6.0.21.Final 5.6.1 @@ -452,6 +451,69 @@ + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + + default-prepare-agent + + prepare-agent + + + + default-prepare-agent-integration + pre-integration-test + + prepare-agent-integration + + + + **/*Test* + + integrationTestArgLine + + + + + default-check + verify + + check + + + + + BUNDLE + + + COMPLEXITY + COVEREDRATIO + 0.10 + + + + + + + + + + + + + + + + default-report + verify + + report + + + + org.eclipse.jetty @@ -459,6 +521,9 @@ 9.4.34.v20201102 foo + + 8080 + 9999 ${project.build.directory}/wisemapping.war automatic @@ -488,9 +553,13 @@ run-forked + true + true 0 + true false - -Ddatabase.base.url=${project.build.directory} + 200 + ${integrationTestArgLine} -Ddatabase.base.url=${project.build.directory} -Djetty.port=8080 @@ -499,6 +568,9 @@ stop + + 1 + @@ -514,6 +586,7 @@ + - + \ No newline at end of file diff --git a/wise-webapp/src/main/java/com/wisemapping/dao/UserManagerImpl.java b/wise-webapp/src/main/java/com/wisemapping/dao/UserManagerImpl.java index 3e5f9893..663fe9d2 100644 --- a/wise-webapp/src/main/java/com/wisemapping/dao/UserManagerImpl.java +++ b/wise-webapp/src/main/java/com/wisemapping/dao/UserManagerImpl.java @@ -52,6 +52,7 @@ public class UserManagerImpl @Override + @Nullable public User getUserBy(@NotNull final String email) { User user = null; diff --git a/wise-webapp/src/main/java/com/wisemapping/exceptions/CollabChangeException.java b/wise-webapp/src/main/java/com/wisemapping/exceptions/CollabChangeException.java new file mode 100755 index 00000000..ee792603 --- /dev/null +++ b/wise-webapp/src/main/java/com/wisemapping/exceptions/CollabChangeException.java @@ -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 CollabChangeException + extends ClientException +{ + + private static final String MSG_KEY = "OWNER_ROLE_CAN_NOT_BE_CHANGED"; + + public CollabChangeException(@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; + } +} diff --git a/wise-webapp/src/main/java/com/wisemapping/exceptions/TooManyInactiveAccountsExceptions.java b/wise-webapp/src/main/java/com/wisemapping/exceptions/TooManyInactiveAccountsExceptions.java new file mode 100755 index 00000000..dc2c8428 --- /dev/null +++ b/wise-webapp/src/main/java/com/wisemapping/exceptions/TooManyInactiveAccountsExceptions.java @@ -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 javax.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; + } +} diff --git a/wise-webapp/src/main/java/com/wisemapping/mail/NotificationService.java b/wise-webapp/src/main/java/com/wisemapping/mail/NotificationService.java index a2f184eb..1a7aaf6c 100644 --- a/wise-webapp/src/main/java/com/wisemapping/mail/NotificationService.java +++ b/wise-webapp/src/main/java/com/wisemapping/mail/NotificationService.java @@ -73,6 +73,11 @@ final public class NotificationService { model.put("message", message); model.put("doNotReplay", messageSource.getMessage("EMAIL.DO_NOT_REPLAY", new Object[]{mailer.getSupportEmail()}, locale)); + // To resolve resources on templates ... + model.put("noArg", new Object[]{}); + model.put("messages", messageSource); + model.put("locale", locale); + mailer.sendEmail(formMail, collabEmail, subject, model, "newCollaboration.vm"); } catch (Exception e) { handleException(e); @@ -122,6 +127,11 @@ final public class NotificationService { model.put("supportEmail", mailer.getSupportEmail()); model.put("doNotReplay", messageSource.getMessage("EMAIL.DO_NOT_REPLAY", new Object[]{mailer.getSupportEmail()}, locale)); + // To resolve resources on templates ... + model.put("noArg", new Object[]{}); + model.put("messages", messageSource); + model.put("locale", locale); + logger.debug("Email properties->" + model); mailer.sendEmail(mailer.getServerSenderEmail(), user.getEmail(), mailSubject, model, "baseLayout.vm"); } catch (Exception e) { diff --git a/wise-webapp/src/main/java/com/wisemapping/model/Mindmap.java b/wise-webapp/src/main/java/com/wisemapping/model/Mindmap.java index bf413899..5cf58ef6 100644 --- a/wise-webapp/src/main/java/com/wisemapping/model/Mindmap.java +++ b/wise-webapp/src/main/java/com/wisemapping/model/Mindmap.java @@ -66,7 +66,7 @@ public class Mindmap implements Serializable { @OneToMany(mappedBy = "mindMap", orphanRemoval = true, cascade = {CascadeType.ALL}) private Set collaborations = new HashSet<>(); - @ManyToMany(cascade = CascadeType.ALL) + @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE}) @JoinTable( name = "R_LABEL_MINDMAP", joinColumns = @JoinColumn(name = "mindmap_id"), diff --git a/wise-webapp/src/main/java/com/wisemapping/rest/AdminController.java b/wise-webapp/src/main/java/com/wisemapping/rest/AdminController.java index ca516dda..352f5681 100644 --- a/wise-webapp/src/main/java/com/wisemapping/rest/AdminController.java +++ b/wise-webapp/src/main/java/com/wisemapping/rest/AdminController.java @@ -1,20 +1,20 @@ /* -* Copyright [2022] [wisemapping] -* -* Licensed under WiseMapping Public License, Version 1.0 (the "License"). -* It is basically the Apache License, Version 2.0 (the "License") plus the -* "powered by wisemapping" text requirement on every single page; -* you may not use this file except in compliance with the License. -* You may obtain a copy of the license at -* -* http://www.wisemapping.org/license -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright [2022] [wisemapping] + * + * Licensed under WiseMapping Public License, Version 1.0 (the "License"). + * It is basically the Apache License, Version 2.0 (the "License") plus the + * "powered by wisemapping" text requirement on every single page; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the license at + * + * http://www.wisemapping.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.wisemapping.rest; @@ -26,19 +26,16 @@ import com.wisemapping.model.User; import com.wisemapping.rest.model.RestUser; import com.wisemapping.service.MindmapService; import com.wisemapping.service.UserService; -import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.Calendar; import java.util.List; -import java.util.regex.Pattern; @Controller public class AdminController extends BaseController { @@ -70,7 +67,7 @@ public class AdminController extends BaseController { return new RestUser(user); } - @RequestMapping(method = RequestMethod.POST, value = "admin/users", consumes = { "application/json"}, produces = {"application/json"}) + @RequestMapping(method = RequestMethod.POST, value = "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) { @@ -109,7 +106,7 @@ public class AdminController extends BaseController { @RequestMapping(method = RequestMethod.PUT, value = "admin/users/{id}/password", consumes = {"text/plain"}) @ResponseStatus(value = HttpStatus.NO_CONTENT) - public void changePassword(@RequestBody String password, @PathVariable int id) throws WiseMappingException { + public void changePassword(@RequestBody String password, @PathVariable int id) throws WiseMappingException { if (password == null) { throw new IllegalArgumentException("Password can not be null"); } @@ -133,7 +130,7 @@ public class AdminController extends BaseController { final List collaborations = mindmapService.findCollaborations(user); for (Collaboration collaboration : collaborations) { final Mindmap mindmap = collaboration.getMindMap(); - mindmapService.removeMindmap(mindmap,user); + mindmapService.removeMindmap(mindmap, user); } userService.removeUser(user); diff --git a/wise-webapp/src/main/java/com/wisemapping/rest/MindmapController.java b/wise-webapp/src/main/java/com/wisemapping/rest/MindmapController.java index c59eb0f2..2d5739c3 100644 --- a/wise-webapp/src/main/java/com/wisemapping/rest/MindmapController.java +++ b/wise-webapp/src/main/java/com/wisemapping/rest/MindmapController.java @@ -29,6 +29,7 @@ import org.apache.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -41,7 +42,6 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; @Controller @@ -58,6 +58,13 @@ public class MindmapController extends BaseController { @Autowired private LabelService labelService; + @Qualifier("userService") + @Autowired + private UserService userService; + + @Value("${accounts.maxInactive:20}") + private int maxAccountsInactive; + @RequestMapping(method = RequestMethod.GET, value = "/maps/{id}", produces = {"application/json"}) @ResponseBody public RestMindmap retrieve(@PathVariable int id) throws WiseMappingException { @@ -169,7 +176,7 @@ public class MindmapController extends BaseController { /** * The intention of this method is the update of several properties at once ... */ - @RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}", consumes = { "application/json"}, produces = {"application/json"}) + @RequestMapping(method = RequestMethod.PUT, value = "/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 { @@ -243,7 +250,7 @@ public class MindmapController extends BaseController { @RequestMapping(method = RequestMethod.POST, value = "/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 { + 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... @@ -252,6 +259,9 @@ public class MindmapController extends BaseController { 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 collabsToRemove = new HashSet<>(mindMap.getCollaborations()); for (RestCollaboration restCollab : restCollabs.getCollaborations()) { @@ -279,7 +289,6 @@ public class MindmapController extends BaseController { if (role != CollaborationRole.OWNER) { mindmapService.addCollaboration(mindMap, restCollab.getEmail(), role, restCollabs.getMessage()); } - } // Remove all collaborations that no applies anymore .. @@ -290,7 +299,7 @@ public class MindmapController extends BaseController { @RequestMapping(method = RequestMethod.PUT, value = "/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 { + public void addCollab(@PathVariable int id, @NotNull @RequestBody RestCollaborationList restCollabs) throws CollaborationException, MapCouldNotFoundException, AccessDeniedSecurityException, InvalidEmailException, TooManyInactiveAccountsExceptions, CollabChangeException { final Mindmap mindMap = findMindmapById(id); // Only owner can change collaborators... @@ -299,6 +308,9 @@ public class MindmapController extends BaseController { 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 invalidEmails = restCollabs @@ -312,41 +324,42 @@ public class MindmapController extends BaseController { } // Has any role changed ?. Just removed it. - final Map mapsByEmail = mindMap + final Map collabByEmail = mindMap .getCollaborations() .stream() .collect(Collectors.toMap(collaboration -> collaboration.getCollaborator().getEmail(), collaboration -> collaboration)); - restCollabs - .getCollaborations() - .forEach(collab -> { - final String email = collab.getEmail(); - if (mapsByEmail.containsKey(email)) { - try { - mindmapService.removeCollaboration(mindMap, mapsByEmail.get(email)); - } catch (CollaborationException e) { - logger.error(e); - } - } - }); - // Great, let's add all the collabs again ... for (RestCollaboration restCollab : restCollabs.getCollaborations()) { - final Collaboration collaboration = mindMap.findCollaboration(restCollab.getEmail()); - // Validate role format ... - String roleStr = restCollab.getRole(); + // Validate newRole format ... + final String roleStr = restCollab.getRole(); if (roleStr == null) { - throw new IllegalArgumentException(roleStr + " is not a valid role"); + throw new IllegalArgumentException(roleStr + " is not a valid newRole"); } - // Is owner ? - final CollaborationRole role = CollaborationRole.valueOf(roleStr.toUpperCase()); - if (role == CollaborationRole.OWNER) { - throw new IllegalArgumentException("Owner can not be added as part of the collaboration list."); - } + // Had the newRole changed ?. Otherwise, don't touch it. + final CollaborationRole newRole = CollaborationRole.valueOf(roleStr.toUpperCase()); + final String collabEmail = restCollab.getEmail(); + final Collaboration currentCollab = collabByEmail.get(collabEmail); + if (currentCollab == null || currentCollab.getRole() != newRole) { - mindmapService.addCollaboration(mindMap, restCollab.getEmail(), role, restCollabs.getMessage()); + // Are we trying to change the owner ... + if (currentCollab != null && currentCollab.getRole() == CollaborationRole.OWNER) { + throw new CollabChangeException(collabEmail); + } + + // Role can not be changed ... + if (newRole == CollaborationRole.OWNER) { + throw new CollabChangeException(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()); + } } } @@ -503,7 +516,7 @@ public class MindmapController extends BaseController { response.setHeader("ResourceId", Integer.toString(mindmap.getId())); } - @RequestMapping(method = RequestMethod.POST, value = "/maps/{id}", consumes = {"application/json"}, produces = { "application/json", "text/plain"}) + @RequestMapping(method = RequestMethod.POST, value = "/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 ... @@ -588,4 +601,25 @@ public class MindmapController extends BaseController { } return result; } + + private void verifyActiveCollabs(@NotNull RestCollaborationList restCollabs, User user) throws TooManyInactiveAccountsExceptions { + // Do not allow more than 20 new accounts per mindmap... + final List userMindmaps = mindmapService.findMindmapsByUser(user); + final Set 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); + } + } } diff --git a/wise-webapp/src/main/java/com/wisemapping/rest/UserController.java b/wise-webapp/src/main/java/com/wisemapping/rest/UserController.java index 64260877..2574ae79 100644 --- a/wise-webapp/src/main/java/com/wisemapping/rest/UserController.java +++ b/wise-webapp/src/main/java/com/wisemapping/rest/UserController.java @@ -38,6 +38,8 @@ import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.util.Arrays; +import java.util.List; @Controller @CrossOrigin @@ -52,6 +54,9 @@ public class UserController extends BaseController { @Value("${google.recaptcha2.enabled}") private Boolean recatchaEnabled; + @Value("${accounts.exclusion.domain:''}") + private String domainBanExclusion; + private static final Logger logger = Logger.getLogger(UserController.class); private static final String REAL_IP_ADDRESS_HEADER = "X-Real-IP"; @@ -115,5 +120,12 @@ public class UserController extends BaseController { if (errors.hasErrors()) { throw errors; } + + // Is excluded ?. + final List 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); + } } } diff --git a/wise-webapp/src/main/java/com/wisemapping/rest/model/RestMindmapHistory.java b/wise-webapp/src/main/java/com/wisemapping/rest/model/RestMindmapHistory.java index bcf4efb2..617991f7 100644 --- a/wise-webapp/src/main/java/com/wisemapping/rest/model/RestMindmapHistory.java +++ b/wise-webapp/src/main/java/com/wisemapping/rest/model/RestMindmapHistory.java @@ -40,15 +40,18 @@ import java.util.TimeZone; public class RestMindmapHistory { static private final SimpleDateFormat sdf; - private final int id; - private final Calendar creation; - private final String creator; + 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(); @@ -61,18 +64,18 @@ public class RestMindmapHistory { } public void setCreationTime() { - } + public String getCreator() { return creator; } - public void setCreator() { - // Do nothing ... + public void setCreator(String creator) { } public void setId(int id) { + this.id=id; } private String toISO8601(@NotNull Date date) { diff --git a/wise-webapp/src/main/java/com/wisemapping/rest/model/RestMindmapList.java b/wise-webapp/src/main/java/com/wisemapping/rest/model/RestMindmapList.java index e2a642a8..aaef046c 100644 --- a/wise-webapp/src/main/java/com/wisemapping/rest/model/RestMindmapList.java +++ b/wise-webapp/src/main/java/com/wisemapping/rest/model/RestMindmapList.java @@ -24,11 +24,7 @@ import com.wisemapping.model.Collaborator; import com.wisemapping.model.Mindmap; import org.jetbrains.annotations.NotNull; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -45,7 +41,7 @@ public class RestMindmapList { this(Collections.emptyList(), null); } - public RestMindmapList(@NotNull List mindmaps, @NotNull Collaborator collaborator) { + public RestMindmapList(@NotNull List mindmaps, Collaborator collaborator) { this.mindmapsInfo = mindmaps.stream() .map(m->new RestMindmapInfo(m, collaborator)) .collect(Collectors.toList()); diff --git a/wise-webapp/src/main/java/com/wisemapping/security/AuthenticationProvider.java b/wise-webapp/src/main/java/com/wisemapping/security/AuthenticationProvider.java index a4240d07..00f433f8 100644 --- a/wise-webapp/src/main/java/com/wisemapping/security/AuthenticationProvider.java +++ b/wise-webapp/src/main/java/com/wisemapping/security/AuthenticationProvider.java @@ -45,6 +45,12 @@ public class AuthenticationProvider implements org.springframework.security.auth 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()); } diff --git a/wise-webapp/src/main/java/com/wisemapping/security/UserDetailsService.java b/wise-webapp/src/main/java/com/wisemapping/security/UserDetailsService.java index a400294a..4a32bf35 100644 --- a/wise-webapp/src/main/java/com/wisemapping/security/UserDetailsService.java +++ b/wise-webapp/src/main/java/com/wisemapping/security/UserDetailsService.java @@ -23,6 +23,7 @@ import com.wisemapping.model.User; import com.wisemapping.service.UserService; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DataAccessException; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -43,77 +44,6 @@ public class UserDetailsService } } -// @Override -// @NotNull -// public UserDetails loadUserDetails(@NotNull OpenIDAuthenticationToken token) throws UsernameNotFoundException { -// -// final User tUser = buildUserFromToken(token); -// final User dbUser = userService.getUserBy(tUser.getEmail()); -// -// final User result; -// if (dbUser != null) { -// if (!token.getIdentityUrl().equals(dbUser.getAuthenticatorUri())) { -// throw new IllegalStateException("Identity url for this user can not change:" + token.getIdentityUrl()); -// } -// result = dbUser; -// } else { -// try { -// tUser.setAuthenticationType(AuthenticationType.OPENID); -// tUser.setAuthenticatorUri(token.getIdentityUrl()); -// -// result = userService.createUser(tUser, false, false); -// } catch (WiseMappingException e) { -// throw new IllegalStateException(e); -// } -// -// } -// return new UserDetails(result, isAdmin(result.getEmail())); -// } - -// @NotNull -// private User buildUserFromToken(@NotNull OpenIDAuthenticationToken token) { -// final User result = new User(); -// -// String lastName = null; -// String firstName = null; -// String email = null; -// String fullName = null; -// -// final List attributes = token.getAttributes(); -// for (OpenIDAttribute attribute : attributes) { -// if (attribute.getName().equals("email")) { -// email = attribute.getValues().get(0); -// } -// -// if (attribute.getName().equals("firstname")) { -// firstName = attribute.getValues().get(0); -// -// } -// -// if (attribute.getName().equals("lastname")) { -// lastName = attribute.getValues().get(0); -// } -// -// if (attribute.getName().equals("fullname")) { -// fullName = attribute.getValues().get(0); -// } -// -// } -// if (lastName == null || firstName == null) { -// result.setFirstname(fullName); -// result.setLastname(""); -// } else { -// result.setLastname(lastName); -// result.setFirstname(firstName); -// } -// result.setEmail(email); -// result.setPassword(""); -// -// final Calendar now = Calendar.getInstance(); -// result.setActivationDate(now); -// return result; -// } - private boolean isAdmin(@Nullable String email) { return email != null && adminUser != null && email.trim().endsWith(adminUser); } diff --git a/wise-webapp/src/main/resources/mail/baseLayout.vm b/wise-webapp/src/main/resources/mail/baseLayout.vm index fe0972b1..4ecadb87 100644 --- a/wise-webapp/src/main/resources/mail/baseLayout.vm +++ b/wise-webapp/src/main/resources/mail/baseLayout.vm @@ -22,13 +22,13 @@
- Hi ${firstName}: + ${messages.getMessage("EMAIL.GREETINGS",$noArgs,$locale)} ${firstName}:

${messageBody}

-

Regards,
- The WiseMapping Team
+

+ The WiseMapping Team

diff --git a/wise-webapp/src/main/resources/mail/confirmationMail.vm b/wise-webapp/src/main/resources/mail/confirmationMail.vm index 5d16c0a9..352cc1b0 100644 --- a/wise-webapp/src/main/resources/mail/confirmationMail.vm +++ b/wise-webapp/src/main/resources/mail/confirmationMail.vm @@ -1,29 +1,29 @@ -

Welcome to WiseMapping!

+
+

Welcome to WiseMapping!

-

- To active your account and verify your e-mail address, please click on the following link. -

-${emailcheck} -

-

- If you have received this mail by error, you do not need to take any action to cancel the account. The account will - not be activated, and you will not receive any further emails. -

+

+ To active your account and verify your e-mail address, please click on the following link. +

+ ${emailcheck} +

+

+ If you have received this mail by error, you do not need to take any action to cancel the account. The account will + not be activated, and you will not receive any further emails. +

-

- If clicking the link above does not work, copy and paste the URL in a new browser window instead. -

+

+ If clicking the link above does not work, copy and paste the URL in a new browser window instead. +

-

- For questions or concerns regarding your account, send us an email to support@wisemapping.com. -

+

+ For questions or concerns regarding your account, send us an email to support@wisemapping.com. +

-

- Cheers,
- The WiseMapping Team. - WiseMapping Site -

+

+ The WiseMapping Team
+

+
- \ No newline at end of file + \ No newline at end of file diff --git a/wise-webapp/src/main/resources/mail/newCollaboration.vm b/wise-webapp/src/main/resources/mail/newCollaboration.vm index b5c49b19..267957be 100755 --- a/wise-webapp/src/main/resources/mail/newCollaboration.vm +++ b/wise-webapp/src/main/resources/mail/newCollaboration.vm @@ -33,6 +33,8 @@
-

${doNotReplay}

+

+ The WiseMapping Team
+

\ No newline at end of file diff --git a/wise-webapp/src/main/resources/messages_de.properties b/wise-webapp/src/main/resources/messages_de.properties index 1e729aae..5ab06621 100644 --- a/wise-webapp/src/main/resources/messages_de.properties +++ b/wise-webapp/src/main/resources/messages_de.properties @@ -66,4 +66,6 @@ MINDMAP_EMPTY_ERROR=Mindmap darf nicht leer sein. INVALID_MINDMAP_FORMAT=Ungültiges Mindmap-Format. TOO_BIG_MINDMAP=Sie haben das Limit von 5000 Themen in einer Mindmap erreicht. SHARE_MAP.EMAIL_SUBJECT={0} hat eine Mindmap mit Ihnen geteilt -EMAIL.DO_NOT_REPLAY=Wichtig: Antworten Sie nicht auf diese E-Mail. Wenn Sie weitere Hilfe benötigen oder Bedenken bezüglich Ihres Kontos haben, kontaktieren Sie uns hier. \ No newline at end of file +EMAIL.DO_NOT_REPLAY=Wichtig: Antworten Sie nicht auf diese E-Mail. Wenn Sie weitere Hilfe benötigen oder Bedenken bezüglich Ihres Kontos haben, kontaktieren Sie uns hier. +EMAIL.GREETINGS=Hallo +OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list. \ No newline at end of file diff --git a/wise-webapp/src/main/resources/messages_en.properties b/wise-webapp/src/main/resources/messages_en.properties index a9c2f181..ef67f540 100644 --- a/wise-webapp/src/main/resources/messages_en.properties +++ b/wise-webapp/src/main/resources/messages_en.properties @@ -67,4 +67,7 @@ PASSWORD_CHANGED.EMAIL_SUBJECT=Your password has been changed PASSWORD_CHANGED.EMAIL_TITLE=Your password has been changed successfully PASSWORD_CHANGED.EMAIL_BODY=

This is only an notification that your password has been changed. No further action is required.

SHARE_MAP.EMAIL_SUBJECT={0} has shared a mind map with you -EMAIL.DO_NOT_REPLAY=Important: Do not reply this email. If you need further help or have any concerns regarding your account, contact us to here. \ No newline at end of file +EMAIL.DO_NOT_REPLAY=Important: Do not reply this email. If you need further help or have any concerns regarding your account, contact us to here. +EMAIL.GREETINGS=Hi +TOO_MANY_INACTIVE_ACCOUNTS=You have shared your mindmaps to more than 20 user that have not registered yet. Please, remove inactive accounts or ask them to register. +OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list. \ No newline at end of file diff --git a/wise-webapp/src/main/resources/messages_es.properties b/wise-webapp/src/main/resources/messages_es.properties index 97e871db..16512ea4 100644 --- a/wise-webapp/src/main/resources/messages_es.properties +++ b/wise-webapp/src/main/resources/messages_es.properties @@ -58,7 +58,7 @@ INVALID_MINDMAP_FORMAT=Formato de mapa mental no válido. TOO_BIG_MINDMAP=Ha alcanzado el límite de 5000 nodos en un mapa mental. REGISTRATION.EMAIL_SUBJECT=Bienvenido/a a WiseMapping ! REGISTRATION.EMAIL_TITLE=Tu cuenta ha sido creada exitosamente -REGISTRATION.EMAIL_BODY=

Gracias por tu interest en WiseMapping. Hace click aqui para empezar a crear y compatir tus mapas mentales. Ideas y sugerencias, no dudes en contactarnos a feedback@wisemapping.com.

+REGISTRATION.EMAIL_BODY=

Gracias por tu interes en WiseMapping. Hace click aqui para empezar a crear y compatir tus mapas mentales. Ideas y sugerencias, no dudes en contactarnos a feedback@wisemapping.com.

CHANGE_PASSWORD.EMAIL_SUBJECT=Su contraseña ha sido restablecida CHANGE_PASSWORD.EMAIL_TITLE=Se ha generado una contraseña temporal CHANGE_PASSWORD.EMAIL_BODY=

Alguien, muy probablemente usted, solicitó una nueva contraseña para su cuenta de WiseMapping.

Esta es su nueva contraseña: {0}

Puede iniciar sesión haciendo clic aquí . Te recomendamos que cambie la contraseña lo antes posible.

@@ -66,4 +66,6 @@ PASSWORD_CHANGED.EMAIL_SUBJECT=Su contraseña ha sido cambiada PASSWORD_CHANGED.EMAIL_TITLE=Su contraseña ha sido cambiada con éxito PASSWORD_CHANGED.EMAIL_BODY=

Esto es solo una notificación de que su contraseña ha sido cambiada. No se requiere ninguna otra acción.

SHARE_MAP.EMAIL_SUBJECT={0} te ha compartido un mapa mental -EMAIL.DO_NOT_REPLAY=Importante: No responda este correo electrónico. Si necesita más ayuda o tiene alguna inquietud con respecto a su cuenta, comuníquese con nosotros a aquí. \ No newline at end of file +EMAIL.DO_NOT_REPLAY=Importante: No responda este correo electrónico. Si necesita más ayuda o tiene alguna inquietud con respecto a su cuenta, comuníquese con nosotros a aquí. +EMAIL.GREETINGS=Hola +OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list. \ No newline at end of file diff --git a/wise-webapp/src/main/resources/messages_fr.properties b/wise-webapp/src/main/resources/messages_fr.properties index b55fe419..3411d942 100644 --- a/wise-webapp/src/main/resources/messages_fr.properties +++ b/wise-webapp/src/main/resources/messages_fr.properties @@ -66,4 +66,6 @@ MINDMAP_EMPTY_ERROR=La carte mentale ne peut pas être vide. INVALID_MINDMAP_FORMAT=Format de carte mentale non valide. TOO_BIG_MINDMAP=Vous avez atteint la limite de 5000 sujets dans une carte mentale. SHARE_MAP.EMAIL_SUBJECT={0} a partagé une carte mentale avec vous -EMAIL.DO_NOT_REPLAY=Important : Ne répondez pas à cet e-mail. Si vous avez besoin d'aide supplémentaire ou si vous avez des inquiétudes concernant votre compte, contactez-nous ici. \ No newline at end of file +EMAIL.DO_NOT_REPLAY=Important : Ne répondez pas à cet e-mail. Si vous avez besoin d'aide supplémentaire ou si vous avez des inquiétudes concernant votre compte, contactez-nous ici. +EMAIL.GREETINGS=Salut +OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list. \ No newline at end of file diff --git a/wise-webapp/src/main/resources/messages_ru.properties b/wise-webapp/src/main/resources/messages_ru.properties index 3caef0fd..5bd75a47 100644 --- a/wise-webapp/src/main/resources/messages_ru.properties +++ b/wise-webapp/src/main/resources/messages_ru.properties @@ -61,3 +61,5 @@ REGISTRATION.EMAIL_TITLE=Ваша учетная запись успешно с REGISTRATION.EMAIL_BODY=

Благодарим вас за интерес к WiseMapping. Нажмите здесь, чтобы начать создавать и публиковать новые интеллект-карты. Если у вас есть какие-либо отзывы или идеи, отправьте нам электронное письмо по адресу feedback@wisemapping.com. Мы будем рады услышать от вас.

SHARE_MAP.EMAIL_SUBJECT={0} has shared a mindmap with you EMAIL.DO_NOT_REPLAY=Important: Do not reply this email. If you need further help or have any concerns regarding your account, contact us to here. +EMAIL.GREETINGS=Hi +OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list. \ No newline at end of file diff --git a/wise-webapp/src/main/resources/messages_zh.properties b/wise-webapp/src/main/resources/messages_zh.properties index d8f323ef..c3b44d80 100644 --- a/wise-webapp/src/main/resources/messages_zh.properties +++ b/wise-webapp/src/main/resources/messages_zh.properties @@ -67,3 +67,5 @@ PASSWORD_CHANGED.EMAIL_TITLE=你已经成功更改密码 PASSWORD_CHANGED.EMAIL_BODY=

这只是您的密码已更改的通知。无需进一步操作。

SHARE_MAP.EMAIL_SUBJECT={0} 与您分享了一张思维导图 EMAIL.DO_NOT_REPLAY=Important: Do not reply this email. If you need further help or have any concerns regarding your account, contact us to here. +EMAIL.GREETINGS=Hi +OWNER_ROLE_CAN_NOT_BE_CHANGED=Owner role can not be change. Please, remove owner from the change list. \ No newline at end of file diff --git a/wise-webapp/src/main/webapp/WEB-INF/app.properties b/wise-webapp/src/main/webapp/WEB-INF/app.properties index 3a01ea34..3cbab059 100755 --- a/wise-webapp/src/main/webapp/WEB-INF/app.properties +++ b/wise-webapp/src/main/webapp/WEB-INF/app.properties @@ -134,6 +134,11 @@ security.ldap.auth.attribute=mail security.ldap.lastName.attribute=sn security.ldap.firstName.attribute=givenName +# User Account filtering policies + +# Coma separated list of domains and emails ban +#accounts.exclusion.domain= + diff --git a/wise-webapp/src/main/webapp/css/viewonly.css b/wise-webapp/src/main/webapp/css/viewonly.css index ebbcf0dd..8969a3c0 100644 --- a/wise-webapp/src/main/webapp/css/viewonly.css +++ b/wise-webapp/src/main/webapp/css/viewonly.css @@ -71,8 +71,13 @@ div#position { background-size: 40px 40px; background-color: #FFF; border-radius: 8px; + padding: 0; } +#position-button>img { + vertical-align: middle; + } + #zoom-button { width: 40px; border: 0; @@ -88,6 +93,13 @@ div#position { background-position: center; cursor: pointer; background-color: #FFF; + padding: 0; +} + +#zoom-plus, +#zoom-minus +>img { + vertical-align: middle; } #zoom-plus { diff --git a/wise-webapp/src/main/webapp/jsp/googleAnalytics.jsf b/wise-webapp/src/main/webapp/jsp/googleAnalytics.jsf deleted file mode 100644 index 2161cee1..00000000 --- a/wise-webapp/src/main/webapp/jsp/googleAnalytics.jsf +++ /dev/null @@ -1,16 +0,0 @@ -<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> - - - - - - - diff --git a/wise-webapp/src/main/webapp/jsp/mindmapEditor.jsp b/wise-webapp/src/main/webapp/jsp/mindmapEditor.jsp index 637bf2cb..d84ea8ae 100644 --- a/wise-webapp/src/main/webapp/jsp/mindmapEditor.jsp +++ b/wise-webapp/src/main/webapp/jsp/mindmapEditor.jsp @@ -23,7 +23,7 @@ diff --git a/wise-webapp/src/main/webapp/jsp/mindmapViewonly.jsp b/wise-webapp/src/main/webapp/jsp/mindmapViewonly.jsp index 88962da4..5b99ed55 100644 --- a/wise-webapp/src/main/webapp/jsp/mindmapViewonly.jsp +++ b/wise-webapp/src/main/webapp/jsp/mindmapViewonly.jsp @@ -7,6 +7,7 @@ + ${mindmap.title} | <spring:message code="SITE.TITLE"/> @@ -15,66 +16,97 @@ - <%@ include file="/jsp/googleAnalytics.jsf" %> + + + + + + + + -
+
+ +
+ + + + + + +
+ :${mindmap.creator.fullName} + :${mindmap.title} +
+ + + +
+
+ + +
+ +
+
+
+
- - - + - -
-
- - -
- -
-
-
- - + const zoomOutButton = document.getElementById('zoom-minus'); + if (zoomOutButton) { + zoomOutButton.addEventListener('click', () => { + designer.zoomOut(); + }); + } + + const position = document.getElementById('position'); + if (position) { + position.addEventListener('click', () => { + designer.zoomToFit(); + }); + } + diff --git a/wise-webapp/src/main/webapp/jsp/reactInclude.jsp b/wise-webapp/src/main/webapp/jsp/reactInclude.jsp index 75dbd7bf..b26af5ca 100644 --- a/wise-webapp/src/main/webapp/jsp/reactInclude.jsp +++ b/wise-webapp/src/main/webapp/jsp/reactInclude.jsp @@ -14,7 +14,7 @@