use of org.eclipse.vorto.repository.core.events.AppEvent in project vorto by eclipse.
the class ModelRepository method removeModel.
@Override
public void removeModel(ModelId modelId) {
doInSession(session -> {
try {
ModelInfo modelResource = this.getById(modelId);
if (modelResource == null) {
throw new ModelNotFoundException("Cannot find '" + modelId.getPrettyFormat() + "' in '" + session.getWorkspace().getName() + "'");
}
if (modelResource.getReferencedBy() != null && !modelResource.getReferencedBy().isEmpty()) {
throw new ModelReferentialIntegrityException("Cannot remove model because it is referenced by other model(s)", modelResource.getReferencedBy());
}
ModelIdHelper modelIdHelper = new ModelIdHelper(modelId);
Item item = session.getItem(modelIdHelper.getFullPath());
item.remove();
session.save();
eventPublisher.publishEvent(new AppEvent(this, modelId, null, EventType.MODEL_DELETED));
return null;
} catch (AccessDeniedException e) {
throw new NotAuthorizedException(modelId, e);
}
});
}
use of org.eclipse.vorto.repository.core.events.AppEvent in project vorto by eclipse.
the class ModelRepository method doAttachFileInSession.
private boolean doAttachFileInSession(ModelId modelId, FileContent fileContent, IUserContext userContext, Session session, Tag[] tags) throws RepositoryException {
try {
ModelIdHelper modelIdHelper = new ModelIdHelper(modelId);
Node modelFolderNode = session.getNode(modelIdHelper.getFullPath());
Node attachmentFolderNode;
if (!modelFolderNode.hasNode(ATTACHMENTS_NODE)) {
attachmentFolderNode = modelFolderNode.addNode(ATTACHMENTS_NODE, NT_FOLDER);
} else {
attachmentFolderNode = modelFolderNode.getNode(ATTACHMENTS_NODE);
}
String[] tagIds = Arrays.stream(tags).filter(Objects::nonNull).map(Tag::getId).collect(Collectors.toList()).toArray(new String[tags.length]);
// purposes), removes the tag from all other attachments
if (Arrays.asList(tags).contains(TAG_DISPLAY_IMAGE)) {
NodeIterator attachments = attachmentFolderNode.getNodes();
while (attachments.hasNext()) {
Node next = attachments.nextNode();
Property attachmentTags = next.getProperty(VORTO_TAGS);
Value[] attachmentTagsValuesFiltered = Arrays.stream(attachmentTags.getValues()).filter(v -> {
try {
return !v.getString().equals(TAG_DISPLAY_IMAGE.getId());
// swallowing here
} catch (RepositoryException re) {
return false;
}
}).toArray(Value[]::new);
next.setProperty(VORTO_TAGS, attachmentTagsValuesFiltered);
}
}
Node contentNode;
if (attachmentFolderNode.hasNode(fileContent.getFileName())) {
Node attachmentNode = attachmentFolderNode.getNode(fileContent.getFileName());
attachmentNode.addMixin(VORTO_META);
attachmentNode.setProperty(VORTO_TAGS, tagIds, PropertyType.STRING);
contentNode = (Node) attachmentNode.getPrimaryItem();
} else {
Node attachmentNode = attachmentFolderNode.addNode(fileContent.getFileName(), NT_FILE);
attachmentNode.addMixin(VORTO_META);
attachmentNode.setProperty(VORTO_TAGS, tagIds, PropertyType.STRING);
contentNode = attachmentNode.addNode(JCR_CONTENT, NT_RESOURCE);
}
Binary binary = session.getValueFactory().createBinary(new ByteArrayInputStream(fileContent.getContent()));
contentNode.setProperty(JCR_DATA, binary);
session.save();
eventPublisher.publishEvent(new AppEvent(this, getById(modelId), userContext, EventType.MODEL_UPDATED));
return true;
} catch (AccessDeniedException e) {
throw new NotAuthorizedException(modelId, e);
}
}
use of org.eclipse.vorto.repository.core.events.AppEvent in project vorto by eclipse.
the class UserService method delete.
/**
* Deletes the given {@link User} and their namespace-role associations, as acted by the given
* acting {@link User}.<br/>
* This can fail for a number of reasons:
* <ul>
* <li>
* The acting {@link User} does not have the {@literal sysadmin} repository role, or is not
* the same {@link User} as the target.
* </li>
* <li>
* The target {@link User} owns a {@link org.eclipse.vorto.repository.domain.Namespace} - in
* which case, ownership should be given to another {@link User} before deleting.
* </li>
* <li>
* The target {@link User} is the only one listed with namespace role {@literal namespace_admin}
* on one or more {@link org.eclipse.vorto.repository.domain.Namespace}s - in which case, the
* role should be given to at least one other {@link User} before deleting.
* </li>
* </ul>
* Failures above will throw checked exceptions. <br/>
* It is also possible that this method will fail by returning {@code false}, should the target
* {@link User} simply not exist.
*
* @param actor
* @param target
* @return
*/
@Transactional(rollbackFor = { OperationForbiddenException.class, DoesNotExistException.class })
public boolean delete(User actor, User target) throws OperationForbiddenException, DoesNotExistException {
// boilerplate null validation
ServiceValidationUtil.validateNulls(actor, target);
if (cache.withUser(target).getUser() == null) {
LOGGER.info("Attempting to delete a user that does not exist. ");
return false;
}
// authorizing actor
userUtil.authorizeActorAsTargetOrSysadmin(actor, target);
// checking if only admin in any namespace
if (userNamespaceRoleService.isOnlyAdminInAnyNamespace(actor, target)) {
throw new OperationForbiddenException("User is the only administrator of at least one namespace - aborting delete operation.");
}
// retrieving namespaces target manages
Collection<Namespace> namespacesManagedByTarget = userNamespaceRoleService.getNamespacesAndRolesByUser(actor, target).entrySet().stream().filter(e -> e.getValue().contains(userNamespaceRoleService.namespaceAdminRole())).map(Entry::getKey).collect(Collectors.toSet());
// target owns at least one namespace - failing
if (!namespacesManagedByTarget.isEmpty()) {
throw new OperationForbiddenException("User is administrator in at least one namespace. Ownership must change before user can be deleted. Aborting operation.");
}
// collecting target user's e-mail address if any
DeleteAccountMessage message = null;
if (target.hasEmailAddress()) {
message = new DeleteAccountMessage(target);
}
// firstly, publish the user deleted event - this way, the models are all anonymized while the
// user and their namespace associations are still there
eventPublisher.publishEvent(new AppEvent(this, target.getUsername(), EventType.USER_DELETED));
// then, retrie namespaces where target has any role
Collection<Namespace> namespacesWhereTargetHasAnyRole = userNamespaceRoleService.getNamespaces(actor, target);
// and remove association for all namespaces
for (Namespace namespace : namespacesWhereTargetHasAnyRole) {
userNamespaceRoleService.deleteAllRoles(actor, target, namespace, false);
}
// finally, delete target user
userRepository.delete(target);
// and send them a message if possible
if (message != null) {
notificationService.sendNotification(message);
}
return true;
}
use of org.eclipse.vorto.repository.core.events.AppEvent in project vorto by eclipse.
the class NamespaceService method create.
// namespace operations
/**
* This creates a new namespace with the given name, setting the given target {@link User} as
* owner, and giving them all available roles on that namespace. <br/>
* The difference between the actor and target users is that depending on the repository roles of
* the actor user, some operations may not succeed.<br/>
* For instance, if the actor and target are the same user (typical situation when a user
* requests to create their own namespace), but the user is not a sysadmin and already has a
* private namespace, the creation would fail (one private namespace per user). <br/>
* However, if the actor was sysadmin and creating, e.g. an official namespace for a target user
* who happens to already have a private namespace, the operation should succeed. <br/>
* The operation can fail the given {@link User} or namespace name are invalid. <br/>
* Examples of invalid {@link User} or namespace are:
* <ul>
* <li>
* The user is {@code null}, has a {@code null} user name, or does not exist.
* </li>
* <li>
* The namespace name is {@code null}, empty, does not conform to naming standards (lowercase
* ASCII alphanumerics, dots as separators, underscores allowed).
* </li>
* <li>
* A namespace with that name already exists.
* </li>
* </ul>
* This method is invoked in two distinct cases:
* <ol>
* <li>
* A user creates their own private namespace.
* </li>
* <li>
* A sysadmin creates an official namespace for any user, including themselves.
* </li>
* </ol>
* This method only deals with creating namespaces. <br/>
*
* @param actor
* @param target
* @param namespaceName
* @return
* @throws IllegalArgumentException
* @throws DoesNotExistException
* @throws CollisionException
* @throws NameSyntaxException
*/
@Transactional(rollbackFor = { DoesNotExistException.class, CollisionException.class, NameSyntaxException.class, PrivateNamespaceQuotaExceededException.class, OperationForbiddenException.class })
public Namespace create(User actor, User target, String namespaceName) throws IllegalArgumentException, DoesNotExistException, CollisionException, NameSyntaxException, PrivateNamespaceQuotaExceededException, OperationForbiddenException {
// boilerplate null validation
ServiceValidationUtil.validate(actor, target);
ServiceValidationUtil.validateNulls(namespaceName);
// lightweight validation of required properties
ServiceValidationUtil.validateNulls(actor.getId(), target.getId());
if (namespaceName.trim().isEmpty()) {
throw new NameSyntaxException(String.format("Namespace name is empty - aborting namespace creation.", namespaceName));
}
// pattern-based namespace name validation
if (!VALID_NAMESPACE_NAME.matcher(namespaceName).matches()) {
throw new NameSyntaxException(String.format("[%s] is not a valid namespace name - aborting namespace creation.", namespaceName));
}
// namespace collision validation
if (cache.namespace(namespaceName).isPresent()) {
throw new CollisionException(String.format("A namespace with name [%s] already exists - aborting namespace creation.", namespaceName));
}
// actor is not sysadmin - need to enforce quota validation and private namespace notation
if (!userRepositoryRoleService.isSysadmin(actor)) {
if (!namespaceName.startsWith(PRIVATE_NAMESPACE_PREFIX)) {
throw new NameSyntaxException(String.format("[%s] is an invalid name for a private namespace - aborting namespace creation.", namespaceName));
}
verifyPrivateNamespaceQuota(actor, target);
}
// persists the new namespace
Namespace namespace = new Namespace();
namespace.setName(namespaceName);
namespace.setWorkspaceId(UUID.randomUUID().toString().replace("-", ""));
namespaceRepository.save(namespace);
userNamespaceRoleService.setAllRoles(actor, target, namespace, true);
// making cache stale so it will load the newly created namespace upon next usage within request
cache.stale();
// application event handling
eventPublisher.publishEvent(new AppEvent(this, target.getUsername(), UserContext.user(target.getUsername(), namespace.getWorkspaceId()), EventType.NAMESPACE_ADDED));
return namespace;
}
use of org.eclipse.vorto.repository.core.events.AppEvent in project vorto by eclipse.
the class ModelRepository method updateProperty.
private ModelId updateProperty(ModelId modelId, NodeConsumer nodeConsumer) {
return doInSession(session -> {
try {
Node folderNode = createNodeForModelId(session, modelId);
Node fileNode = folderNode.getNodes(FILE_NODES).hasNext() ? folderNode.getNodes(FILE_NODES).nextNode() : null;
nodeConsumer.accept(fileNode);
fileNode.addMixin(MIX_LAST_MODIFIED);
session.save();
eventPublisher.publishEvent(new AppEvent(this, getBasicInfo(modelId), null, EventType.MODEL_UPDATED));
return modelId;
} catch (AccessDeniedException e) {
throw new NotAuthorizedException(modelId, e);
}
});
}
Aggregations