package io.lumify.web.routes.workspace; import com.google.common.base.Function; import com.google.common.collect.Iterables; import com.google.inject.Inject; import io.lumify.core.config.Configuration; import io.lumify.core.model.notification.ExpirationAge; import io.lumify.core.model.notification.ExpirationAgeUnit; import io.lumify.core.model.notification.UserNotificationRepository; import io.lumify.core.model.user.UserRepository; import io.lumify.core.model.workQueue.WorkQueueRepository; import io.lumify.core.model.workspace.Workspace; import io.lumify.core.model.workspace.WorkspaceRepository; import io.lumify.core.user.User; import io.lumify.core.util.LumifyLogger; import io.lumify.core.util.LumifyLoggerFactory; import io.lumify.miniweb.HandlerChain; import io.lumify.web.BaseRequestHandler; import io.lumify.web.clientapi.model.ClientApiWorkspace; import io.lumify.web.clientapi.model.ClientApiWorkspaceUpdateData; import io.lumify.web.clientapi.model.GraphPosition; import io.lumify.web.clientapi.model.WorkspaceAccess; import io.lumify.web.clientapi.model.util.ObjectMapperFactory; import org.json.JSONObject; import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.text.MessageFormat; import java.util.List; import java.util.ResourceBundle; public class WorkspaceUpdate extends BaseRequestHandler { private static final LumifyLogger LOGGER = LumifyLoggerFactory.getLogger(WorkspaceUpdate.class); private final WorkspaceRepository workspaceRepository; private final WorkQueueRepository workQueueRepository; private final UserNotificationRepository userNotificationRepository; @Inject public WorkspaceUpdate( final WorkspaceRepository workspaceRepository, final UserRepository userRepository, final WorkQueueRepository workQueueRepository, final UserNotificationRepository userNotificationRepository, final Configuration configuration) { super(userRepository, workspaceRepository, configuration); this.workspaceRepository = workspaceRepository; this.workQueueRepository = workQueueRepository; this.userNotificationRepository = userNotificationRepository; } @Override public void handle(HttpServletRequest request, HttpServletResponse response, HandlerChain chain) throws Exception { final String workspaceId = getActiveWorkspaceId(request); final String data = getRequiredParameter(request, "data"); User authUser = getUser(request); Workspace workspace = workspaceRepository.findById(workspaceId, authUser); if (workspace == null) { respondWithNotFound(response); return; } ClientApiWorkspaceUpdateData updateData = ObjectMapperFactory.getInstance().readValue(data, ClientApiWorkspaceUpdateData.class); if (updateData.getTitle() != null) { setTitle(workspace, updateData.getTitle(), authUser); } updateEntities(workspace, updateData.getEntityUpdates(), authUser); deleteEntities(workspace, updateData.getEntityDeletes(), authUser); ResourceBundle resource = getBundle(request); String title = resource.getString("workspaces.notification.shared.title"); String message = resource.getString("workspaces.notification.shared.subtitle"); updateUsers(workspace, updateData.getUserUpdates(), authUser, title, message); workspace = workspaceRepository.findById(workspaceId, authUser); ClientApiWorkspace clientApiWorkspaceAfterUpdateButBeforeDelete = workspaceRepository.toClientApi(workspace, authUser, true); List<ClientApiWorkspace.User> previousUsers = clientApiWorkspaceAfterUpdateButBeforeDelete.getUsers(); deleteUsers(workspace, updateData.getUserDeletes(), authUser); ClientApiWorkspace clientApiWorkspace = workspaceRepository.toClientApi(workspace, authUser, true); respondWithSuccessJson(response); workQueueRepository.pushWorkspaceChange(clientApiWorkspace, previousUsers, authUser.getUserId()); } private void setTitle(Workspace workspace, String title, User authUser) { LOGGER.debug("setting title (%s): %s", workspace.getWorkspaceId(), title); workspaceRepository.setTitle(workspace, title, authUser); } private void deleteUsers(Workspace workspace, List<String> userDeletes, User authUser) { for (String userId : userDeletes) { LOGGER.debug("user delete (%s): %s", workspace.getWorkspaceId(), userId); workspaceRepository.deleteUserFromWorkspace(workspace, userId, authUser); workQueueRepository.pushWorkspaceDelete(workspace.getWorkspaceId(), userId); } } private void updateUsers(Workspace workspace, List<ClientApiWorkspaceUpdateData.UserUpdate> userUpdates, User authUser, String title, String subtitle) { for (ClientApiWorkspaceUpdateData.UserUpdate update : userUpdates) { LOGGER.debug("user update (%s): %s", workspace.getWorkspaceId(), update.toString()); String userId = update.getUserId(); WorkspaceAccess workspaceAccess = update.getAccess(); workspaceRepository.updateUserOnWorkspace(workspace, userId, workspaceAccess, authUser); String message = MessageFormat.format(subtitle, authUser.getDisplayName(), workspace.getDisplayTitle()); JSONObject payload = new JSONObject(); payload.put("workspaceId", workspace.getWorkspaceId()); userNotificationRepository.createNotification(userId, title, message, "switchWorkspace", payload, new ExpirationAge(7, ExpirationAgeUnit.DAY)); } } private void deleteEntities(Workspace workspace, List<String> entityIdsToDelete, User authUser) { workspaceRepository.softDeleteEntitiesFromWorkspace(workspace, entityIdsToDelete, authUser); } private void updateEntities(Workspace workspace, List<ClientApiWorkspaceUpdateData.EntityUpdate> entityUpdates, User authUser) { Iterable<WorkspaceRepository.Update> updates = Iterables.transform(entityUpdates, new Function<ClientApiWorkspaceUpdateData.EntityUpdate, WorkspaceRepository.Update>() { @Nullable @Override public WorkspaceRepository.Update apply(ClientApiWorkspaceUpdateData.EntityUpdate u) { String vertexId = u.getVertexId(); GraphPosition graphPosition = u.getGraphPosition(); String graphLayoutJson = u.getGraphLayoutJson(); return new WorkspaceRepository.Update(vertexId, true, graphPosition, graphLayoutJson); } }); workspaceRepository.updateEntitiesOnWorkspace(workspace, updates, authUser); } }