Add control to limit the number of accounts to share.

This commit is contained in:
Paulo Gustavo Veiga 2022-04-11 16:58:06 -03:00
parent c6ddadba45
commit 7af7925610
4 changed files with 76 additions and 7 deletions

View File

@ -52,6 +52,7 @@ public class UserManagerImpl
@Override @Override
@Nullable
public User getUserBy(@NotNull final String email) { public User getUserBy(@NotNull final String email) {
User user = null; User user = null;

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

View File

@ -41,7 +41,6 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
@Controller @Controller
@ -49,6 +48,7 @@ public class MindmapController extends BaseController {
final Logger logger = Logger.getLogger(MindmapController.class); final Logger logger = Logger.getLogger(MindmapController.class);
private static final String LATEST_HISTORY_REVISION = "latest"; private static final String LATEST_HISTORY_REVISION = "latest";
private static final int MAX_ACCOUNTS_INACTIVE = 20;
@Qualifier("mindmapService") @Qualifier("mindmapService")
@Autowired @Autowired
@ -58,6 +58,10 @@ public class MindmapController extends BaseController {
@Autowired @Autowired
private LabelService labelService; private LabelService labelService;
@Qualifier("userService")
@Autowired
private UserService userService;
@RequestMapping(method = RequestMethod.GET, value = "/maps/{id}", produces = {"application/json"}) @RequestMapping(method = RequestMethod.GET, value = "/maps/{id}", produces = {"application/json"})
@ResponseBody @ResponseBody
public RestMindmap retrieve(@PathVariable int id) throws WiseMappingException { public RestMindmap retrieve(@PathVariable int id) throws WiseMappingException {
@ -169,7 +173,7 @@ public class MindmapController extends BaseController {
/** /**
* The intention of this method is the update of several properties at once ... * 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) @ResponseStatus(value = HttpStatus.NO_CONTENT)
public void updateProperties(@RequestBody RestMindmap restMindmap, @PathVariable int id, @RequestParam(required = false) boolean minor) throws IOException, WiseMappingException { public void updateProperties(@RequestBody RestMindmap restMindmap, @PathVariable int id, @RequestParam(required = false) boolean minor) throws IOException, WiseMappingException {
@ -243,7 +247,7 @@ public class MindmapController extends BaseController {
@RequestMapping(method = RequestMethod.POST, value = "/maps/{id}/collabs/", consumes = {"application/json"}, produces = {"application/json"}) @RequestMapping(method = RequestMethod.POST, value = "/maps/{id}/collabs/", consumes = {"application/json"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT) @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); final Mindmap mindMap = findMindmapById(id);
// Only owner can change collaborators... // Only owner can change collaborators...
@ -252,6 +256,9 @@ public class MindmapController extends BaseController {
throw new IllegalArgumentException("No enough permissions"); 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 .... // Compare one by one if some of the elements has been changed ....
final Set<Collaboration> collabsToRemove = new HashSet<>(mindMap.getCollaborations()); final Set<Collaboration> collabsToRemove = new HashSet<>(mindMap.getCollaborations());
for (RestCollaboration restCollab : restCollabs.getCollaborations()) { for (RestCollaboration restCollab : restCollabs.getCollaborations()) {
@ -279,7 +286,6 @@ public class MindmapController extends BaseController {
if (role != CollaborationRole.OWNER) { if (role != CollaborationRole.OWNER) {
mindmapService.addCollaboration(mindMap, restCollab.getEmail(), role, restCollabs.getMessage()); mindmapService.addCollaboration(mindMap, restCollab.getEmail(), role, restCollabs.getMessage());
} }
} }
// Remove all collaborations that no applies anymore .. // Remove all collaborations that no applies anymore ..
@ -290,7 +296,7 @@ public class MindmapController extends BaseController {
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/collabs/", consumes = {"application/json"}, produces = {"application/json"}) @RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/collabs/", consumes = {"application/json"}, produces = {"application/json"})
@ResponseStatus(value = HttpStatus.NO_CONTENT) @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 {
final Mindmap mindMap = findMindmapById(id); final Mindmap mindMap = findMindmapById(id);
// Only owner can change collaborators... // Only owner can change collaborators...
@ -299,6 +305,9 @@ public class MindmapController extends BaseController {
throw new AccessDeniedSecurityException("User must be owner to share mindmap"); 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 ? // Is valid email address ?
final EmailValidator emailValidator = EmailValidator.getInstance(); final EmailValidator emailValidator = EmailValidator.getInstance();
final Set<String> invalidEmails = restCollabs final Set<String> invalidEmails = restCollabs
@ -503,7 +512,7 @@ public class MindmapController extends BaseController {
response.setHeader("ResourceId", Integer.toString(mindmap.getId())); 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) @ResponseStatus(value = HttpStatus.CREATED)
public void createDuplicate(@RequestBody RestMindmapInfo restMindmap, @PathVariable int id, @NotNull HttpServletResponse response) throws IOException, WiseMappingException { public void createDuplicate(@RequestBody RestMindmapInfo restMindmap, @PathVariable int id, @NotNull HttpServletResponse response) throws IOException, WiseMappingException {
// Validate ... // Validate ...
@ -588,4 +597,25 @@ public class MindmapController extends BaseController {
} }
return result; return 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 > MAX_ACCOUNTS_INACTIVE) {
throw new TooManyInactiveAccountsExceptions(inactiveAccounts);
}
}
} }

View File

@ -68,4 +68,5 @@ PASSWORD_CHANGED.EMAIL_TITLE=Your password has been changed successfully
PASSWORD_CHANGED.EMAIL_BODY=<p>This is only an notification that your password has been changed. No further action is required.</p> PASSWORD_CHANGED.EMAIL_BODY=<p>This is only an notification that your password has been changed. No further action is required.</p>
SHARE_MAP.EMAIL_SUBJECT={0} has shared a mind map with you 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 <a href="mailto:{0}">here</a>. 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 <a href="mailto:{0}">here</a>.
EMAIL.GREETINGS=Hi 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.