Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

convert the workspace update api to patch style #16739

Merged
merged 3 commits into from
Sep 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions airbyte-api/src/main/openapi/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2395,12 +2395,9 @@ components:
type: string
WorkspaceUpdate:
type: object
description: Used to apply a patch-style update to a workspace, which means that null properties remain unchanged
required:
- workspaceId
- initialSetupComplete
- anonymousDataCollection
- news
- securityUpdates
properties:
workspaceId:
$ref: "#/components/schemas/WorkspaceId"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package io.airbyte.server.handlers;

import com.github.slugify.Slugify;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import io.airbyte.analytics.TrackingClientSingleton;
import io.airbyte.api.model.generated.ConnectionRead;
Expand Down Expand Up @@ -36,9 +37,12 @@
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WorkspacesHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(WorkspacesHandler.class);
private final ConfigRepository configRepository;
private final ConnectionsHandler connectionsHandler;
private final DestinationHandler destinationHandler;
Expand Down Expand Up @@ -143,29 +147,28 @@ public WorkspaceRead getWorkspaceBySlug(final SlugRequestBody slugRequestBody)
return buildWorkspaceRead(workspace);
}

public WorkspaceRead updateWorkspace(final WorkspaceUpdate workspaceUpdate) throws ConfigNotFoundException, IOException, JsonValidationException {
final UUID workspaceId = workspaceUpdate.getWorkspaceId();
public WorkspaceRead updateWorkspace(final WorkspaceUpdate workspacePatch) throws ConfigNotFoundException, IOException, JsonValidationException {
final UUID workspaceId = workspacePatch.getWorkspaceId();

final StandardWorkspace persistedWorkspace = configRepository.getStandardWorkspace(workspaceId, false);
LOGGER.debug("Starting updateWorkspace for workspaceId {}...", workspaceId);
LOGGER.debug("Incoming workspacePatch: {}", workspacePatch);

if (!Strings.isNullOrEmpty(workspaceUpdate.getEmail())) {
persistedWorkspace.withEmail(workspaceUpdate.getEmail());
}
final StandardWorkspace workspace = configRepository.getStandardWorkspace(workspaceId, false);
LOGGER.debug("Initial workspace: {}", workspace);

persistedWorkspace
.withInitialSetupComplete(workspaceUpdate.getInitialSetupComplete())
.withDisplaySetupWizard(workspaceUpdate.getDisplaySetupWizard())
.withAnonymousDataCollection(workspaceUpdate.getAnonymousDataCollection())
.withNews(workspaceUpdate.getNews())
.withSecurityUpdates(workspaceUpdate.getSecurityUpdates())
.withNotifications(NotificationConverter.toConfigList(workspaceUpdate.getNotifications()));
validateWorkspacePatch(workspace, workspacePatch);

configRepository.writeStandardWorkspace(persistedWorkspace);
LOGGER.debug("Initial WorkspaceRead: {}", buildWorkspaceRead(workspace));

applyPatchToStandardWorkspace(workspace, workspacePatch);

LOGGER.debug("Patched Workspace before persisting: {}", workspace);
configRepository.writeStandardWorkspace(workspace);

// after updating email or tracking info, we need to re-identify the instance.
TrackingClientSingleton.get().identify(workspaceId);

return buildWorkspaceReadFromId(workspaceUpdate.getWorkspaceId());
return buildWorkspaceReadFromId(workspaceId);
}

public WorkspaceRead updateWorkspaceName(final WorkspaceUpdateName workspaceUpdateName)
Expand Down Expand Up @@ -249,4 +252,32 @@ private static WorkspaceRead buildWorkspaceRead(final StandardWorkspace workspac
.notifications(NotificationConverter.toApiList(workspace.getNotifications()));
}

private void validateWorkspacePatch(final StandardWorkspace persistedWorkspace, final WorkspaceUpdate workspacePatch) {
Preconditions.checkArgument(persistedWorkspace.getWorkspaceId().equals(workspacePatch.getWorkspaceId()));
}

private void applyPatchToStandardWorkspace(final StandardWorkspace workspace, final WorkspaceUpdate workspacePatch) {
if (workspacePatch.getAnonymousDataCollection() != null) {
workspace.setAnonymousDataCollection(workspacePatch.getAnonymousDataCollection());
}
if (workspacePatch.getNews() != null) {
workspace.setNews(workspacePatch.getNews());
}
if (workspacePatch.getDisplaySetupWizard() != null) {
workspace.setDisplaySetupWizard(workspacePatch.getDisplaySetupWizard());
}
if (workspacePatch.getSecurityUpdates() != null) {
workspace.setSecurityUpdates(workspacePatch.getSecurityUpdates());
}
if (!Strings.isNullOrEmpty(workspacePatch.getEmail())) {
workspace.setEmail(workspacePatch.getEmail());
}
if (workspacePatch.getInitialSetupComplete() != null) {
workspace.setInitialSetupComplete(workspacePatch.getInitialSetupComplete());
}
if (workspacePatch.getNotifications() != null) {
workspace.setNotifications(NotificationConverter.toConfigList(workspacePatch.getNotifications()));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,38 @@ void testUpdateWorkspaceNoNameUpdate() throws JsonValidationException, ConfigNot
assertEquals(expectedWorkspaceRead, actualWorkspaceRead);
}

@Test
@DisplayName("Partial patch update should preserve unchanged fields")
void testWorkspacePatchUpdate() throws JsonValidationException, ConfigNotFoundException, IOException {
final String EXPECTED_NEW_EMAIL = "[email protected]";
final WorkspaceUpdate workspaceUpdate = new WorkspaceUpdate()
.workspaceId(workspace.getWorkspaceId())
.anonymousDataCollection(true)
.email(EXPECTED_NEW_EMAIL);

final StandardWorkspace expectedWorkspace = Jsons.clone(workspace).withEmail(EXPECTED_NEW_EMAIL).withAnonymousDataCollection(true);
when(configRepository.getStandardWorkspace(workspace.getWorkspaceId(), false))
.thenReturn(workspace)
.thenReturn(expectedWorkspace);
// The same as the original workspace, with only the email and data collection flags changed.
final WorkspaceRead expectedWorkspaceRead = new WorkspaceRead()
.workspaceId(workspace.getWorkspaceId())
.customerId(workspace.getCustomerId())
.email(EXPECTED_NEW_EMAIL)
.name(workspace.getName())
.slug(workspace.getSlug())
.initialSetupComplete(workspace.getInitialSetupComplete())
.displaySetupWizard(workspace.getDisplaySetupWizard())
.news(workspace.getNews())
.anonymousDataCollection(true)
.securityUpdates(workspace.getSecurityUpdates())
.notifications(NotificationConverter.toApiList(workspace.getNotifications()));

final WorkspaceRead actualWorkspaceRead = workspacesHandler.updateWorkspace(workspaceUpdate);
verify(configRepository).writeStandardWorkspace(expectedWorkspace);
assertEquals(expectedWorkspaceRead, actualWorkspaceRead);
}

@Test
void testSetFeedbackDone() throws JsonValidationException, ConfigNotFoundException, IOException {
final WorkspaceGiveFeedback workspaceGiveFeedback = new WorkspaceGiveFeedback()
Expand Down
10 changes: 5 additions & 5 deletions docs/reference/api/generated-api-html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11928,15 +11928,15 @@ <h3><a name="WorkspaceReadList"><code>WorkspaceReadList</code> - </a> <a class="
</div>
<div class="model">
<h3><a name="WorkspaceUpdate"><code>WorkspaceUpdate</code> - </a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class='model-description'>Used to apply a patch-style update to a workspace, which means that null properties remain unchanged</div>
<div class="field-items">
<div class="param">workspaceId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">email (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> format: email</div>
<div class="param">initialSetupComplete </div><div class="param-desc"><span class="param-type"><a href="#boolean">Boolean</a></span> </div>
<div class="param">initialSetupComplete (optional)</div><div class="param-desc"><span class="param-type"><a href="#boolean">Boolean</a></span> </div>
<div class="param">displaySetupWizard (optional)</div><div class="param-desc"><span class="param-type"><a href="#boolean">Boolean</a></span> </div>
<div class="param">anonymousDataCollection </div><div class="param-desc"><span class="param-type"><a href="#boolean">Boolean</a></span> </div>
<div class="param">news </div><div class="param-desc"><span class="param-type"><a href="#boolean">Boolean</a></span> </div>
<div class="param">securityUpdates </div><div class="param-desc"><span class="param-type"><a href="#boolean">Boolean</a></span> </div>
<div class="param">anonymousDataCollection (optional)</div><div class="param-desc"><span class="param-type"><a href="#boolean">Boolean</a></span> </div>
<div class="param">news (optional)</div><div class="param-desc"><span class="param-type"><a href="#boolean">Boolean</a></span> </div>
<div class="param">securityUpdates (optional)</div><div class="param-desc"><span class="param-type"><a href="#boolean">Boolean</a></span> </div>
<div class="param">notifications (optional)</div><div class="param-desc"><span class="param-type"><a href="#Notification">array[Notification]</a></span> </div>
</div> <!-- field-items -->
</div>
Expand Down