Skip to content

Commit 8f22595

Browse files
author
Tim Roes
authored
Allow updating workspace names (#9686)
* Allow updating workspace names * Add additional unit test * Fix code styling * Update slug as well * Update indentations * Pull name update into separate endpoint
1 parent c873898 commit 8f22595

File tree

5 files changed

+194
-0
lines changed

5 files changed

+194
-0
lines changed

airbyte-api/src/main/openapi/config.yaml

+33
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,29 @@ paths:
185185
$ref: "#/components/responses/NotFoundResponse"
186186
"422":
187187
$ref: "#/components/responses/InvalidInputResponse"
188+
/v1/workspaces/update_name:
189+
post:
190+
tags:
191+
- workspace
192+
summary: Update workspace name
193+
operationId: updateWorkspaceName
194+
requestBody:
195+
content:
196+
application/json:
197+
schema:
198+
$ref: "#/components/schemas/WorkspaceUpdateName"
199+
required: true
200+
responses:
201+
"200":
202+
description: Successful operation
203+
content:
204+
application/json:
205+
schema:
206+
$ref: "#/components/schemas/WorkspaceRead"
207+
"404":
208+
$ref: "#/components/responses/NotFoundResponse"
209+
"422":
210+
$ref: "#/components/responses/InvalidInputResponse"
188211
/v1/workspaces/tag_feedback_status_as_done:
189212
post:
190213
tags:
@@ -1972,6 +1995,16 @@ components:
19721995
type: boolean
19731996
feedbackDone:
19741997
type: boolean
1998+
WorkspaceUpdateName:
1999+
type: object
2000+
required:
2001+
- workspaceId
2002+
- name
2003+
properties:
2004+
workspaceId:
2005+
$ref: "#/components/schemas/WorkspaceId"
2006+
name:
2007+
type: string
19752008
WorkspaceUpdate:
19762009
type: object
19772010
required:

airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java

+6
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import io.airbyte.api.model.WorkspaceRead;
8383
import io.airbyte.api.model.WorkspaceReadList;
8484
import io.airbyte.api.model.WorkspaceUpdate;
85+
import io.airbyte.api.model.WorkspaceUpdateName;
8586
import io.airbyte.commons.features.FeatureFlags;
8687
import io.airbyte.commons.io.FileTtlManager;
8788
import io.airbyte.commons.version.AirbyteVersion;
@@ -266,6 +267,11 @@ public WorkspaceRead updateWorkspace(final WorkspaceUpdate workspaceUpdate) {
266267
return execute(() -> workspacesHandler.updateWorkspace(workspaceUpdate));
267268
}
268269

270+
@Override
271+
public WorkspaceRead updateWorkspaceName(final WorkspaceUpdateName workspaceUpdateName) {
272+
return execute(() -> workspacesHandler.updateWorkspaceName(workspaceUpdateName));
273+
}
274+
269275
@Override
270276
public void updateWorkspaceFeedback(final WorkspaceGiveFeedback workspaceGiveFeedback) {
271277
execute(() -> {

airbyte-server/src/main/java/io/airbyte/server/handlers/WorkspacesHandler.java

+16
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.airbyte.api.model.WorkspaceRead;
2121
import io.airbyte.api.model.WorkspaceReadList;
2222
import io.airbyte.api.model.WorkspaceUpdate;
23+
import io.airbyte.api.model.WorkspaceUpdateName;
2324
import io.airbyte.config.StandardWorkspace;
2425
import io.airbyte.config.persistence.ConfigNotFoundException;
2526
import io.airbyte.config.persistence.ConfigRepository;
@@ -167,6 +168,21 @@ public WorkspaceRead updateWorkspace(final WorkspaceUpdate workspaceUpdate) thro
167168
return buildWorkspaceReadFromId(workspaceUpdate.getWorkspaceId());
168169
}
169170

171+
public WorkspaceRead updateWorkspaceName(final WorkspaceUpdateName workspaceUpdateName)
172+
throws JsonValidationException, ConfigNotFoundException, IOException {
173+
final UUID workspaceId = workspaceUpdateName.getWorkspaceId();
174+
175+
final StandardWorkspace persistedWorkspace = configRepository.getStandardWorkspace(workspaceId, false);
176+
177+
persistedWorkspace
178+
.withName(workspaceUpdateName.getName())
179+
.withSlug(generateUniqueSlug(workspaceUpdateName.getName()));
180+
181+
configRepository.writeStandardWorkspace(persistedWorkspace);
182+
183+
return buildWorkspaceReadFromId(workspaceId);
184+
}
185+
170186
public NotificationRead tryNotification(final Notification notification) {
171187
try {
172188
final NotificationClient notificationClient = NotificationClient.createNotificationClient(NotificationConverter.toConfig(notification));

airbyte-server/src/test/java/io/airbyte/server/handlers/WorkspacesHandlerTest.java

+47
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.airbyte.api.model.WorkspaceRead;
2929
import io.airbyte.api.model.WorkspaceReadList;
3030
import io.airbyte.api.model.WorkspaceUpdate;
31+
import io.airbyte.api.model.WorkspaceUpdateName;
3132
import io.airbyte.commons.json.Jsons;
3233
import io.airbyte.config.Notification;
3334
import io.airbyte.config.Notification.NotificationType;
@@ -44,6 +45,7 @@
4445
import java.util.UUID;
4546
import java.util.function.Supplier;
4647
import org.junit.jupiter.api.BeforeEach;
48+
import org.junit.jupiter.api.DisplayName;
4749
import org.junit.jupiter.api.Test;
4850
import org.mockito.ArgumentCaptor;
4951

@@ -344,6 +346,51 @@ void testUpdateWorkspace() throws JsonValidationException, ConfigNotFoundExcepti
344346
assertEquals(expectedWorkspaceRead, actualWorkspaceRead);
345347
}
346348

349+
@Test
350+
@DisplayName("Updating workspace name should update name and slug")
351+
void testUpdateWorkspaceNoNameUpdate() throws JsonValidationException, ConfigNotFoundException, IOException {
352+
final WorkspaceUpdateName workspaceUpdate = new WorkspaceUpdateName()
353+
.workspaceId(workspace.getWorkspaceId())
354+
.name("New Workspace Name");
355+
356+
final StandardWorkspace expectedWorkspace = new StandardWorkspace()
357+
.withWorkspaceId(workspace.getWorkspaceId())
358+
.withCustomerId(workspace.getCustomerId())
359+
.withEmail("[email protected]")
360+
.withName("New Workspace Name")
361+
.withSlug("new-workspace-name")
362+
.withAnonymousDataCollection(workspace.getAnonymousDataCollection())
363+
.withSecurityUpdates(workspace.getSecurityUpdates())
364+
.withNews(workspace.getNews())
365+
.withInitialSetupComplete(workspace.getInitialSetupComplete())
366+
.withDisplaySetupWizard(workspace.getDisplaySetupWizard())
367+
.withTombstone(false)
368+
.withNotifications(workspace.getNotifications());
369+
370+
when(configRepository.getStandardWorkspace(workspace.getWorkspaceId(), false))
371+
.thenReturn(workspace)
372+
.thenReturn(expectedWorkspace);
373+
374+
final WorkspaceRead actualWorkspaceRead = workspacesHandler.updateWorkspaceName(workspaceUpdate);
375+
376+
final WorkspaceRead expectedWorkspaceRead = new WorkspaceRead()
377+
.workspaceId(workspace.getWorkspaceId())
378+
.customerId(workspace.getCustomerId())
379+
380+
.name("New Workspace Name")
381+
.slug("new-workspace-name")
382+
.initialSetupComplete(workspace.getInitialSetupComplete())
383+
.displaySetupWizard(workspace.getDisplaySetupWizard())
384+
.news(workspace.getNews())
385+
.anonymousDataCollection(workspace.getAnonymousDataCollection())
386+
.securityUpdates(workspace.getSecurityUpdates())
387+
.notifications(List.of(generateApiNotification()));
388+
389+
verify(configRepository).writeStandardWorkspace(expectedWorkspace);
390+
391+
assertEquals(expectedWorkspaceRead, actualWorkspaceRead);
392+
}
393+
347394
@Test
348395
public void testSetFeedbackDone() throws JsonValidationException, ConfigNotFoundException, IOException {
349396
final WorkspaceGiveFeedback workspaceGiveFeedback = new WorkspaceGiveFeedback()

docs/reference/api/generated-api-html/index.html

+92
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ <h4><a href="#Workspace">Workspace</a></h4>
359359
<li><a href="#listWorkspaces"><code><span class="http-method">post</span> /v1/workspaces/list</code></a></li>
360360
<li><a href="#updateWorkspace"><code><span class="http-method">post</span> /v1/workspaces/update</code></a></li>
361361
<li><a href="#updateWorkspaceFeedback"><code><span class="http-method">post</span> /v1/workspaces/tag_feedback_status_as_done</code></a></li>
362+
<li><a href="#updateWorkspaceName"><code><span class="http-method">post</span> /v1/workspaces/update_name</code></a></li>
362363
</ul>
363364

364365
<h1><a name="Connection">Connection</a></h1>
@@ -7447,6 +7448,88 @@ <h4 class="field-label">404</h4>
74477448
<a href="#NotFoundKnownExceptionInfo">NotFoundKnownExceptionInfo</a>
74487449
</div> <!-- method -->
74497450
<hr/>
7451+
<div class="method"><a name="updateWorkspaceName"/>
7452+
<div class="method-path">
7453+
<a class="up" href="#__Methods">Up</a>
7454+
<pre class="post"><code class="huge"><span class="http-method">post</span> /v1/workspaces/update_name</code></pre></div>
7455+
<div class="method-summary">Update workspace name (<span class="nickname">updateWorkspaceName</span>)</div>
7456+
<div class="method-notes"></div>
7457+
7458+
7459+
<h3 class="field-label">Consumes</h3>
7460+
This API call consumes the following media types via the <span class="header">Content-Type</span> request header:
7461+
<ul>
7462+
<li><code>application/json</code></li>
7463+
</ul>
7464+
7465+
<h3 class="field-label">Request body</h3>
7466+
<div class="field-items">
7467+
<div class="param">WorkspaceUpdateName <a href="#WorkspaceUpdateName">WorkspaceUpdateName</a> (required)</div>
7468+
7469+
<div class="param-desc"><span class="param-type">Body Parameter</span> &mdash; </div>
7470+
7471+
</div> <!-- field-items -->
7472+
7473+
7474+
7475+
7476+
<h3 class="field-label">Return type</h3>
7477+
<div class="return-type">
7478+
<a href="#WorkspaceRead">WorkspaceRead</a>
7479+
7480+
</div>
7481+
7482+
<!--Todo: process Response Object and its headers, schema, examples -->
7483+
7484+
<h3 class="field-label">Example data</h3>
7485+
<div class="example-data-content-type">Content-Type: application/json</div>
7486+
<pre class="example"><code>{
7487+
"news" : true,
7488+
"displaySetupWizard" : true,
7489+
"initialSetupComplete" : true,
7490+
"anonymousDataCollection" : true,
7491+
"customerId" : "046b6c7f-0b8a-43b9-b35d-6489e6daee91",
7492+
"name" : "name",
7493+
"firstCompletedSync" : true,
7494+
"feedbackDone" : true,
7495+
"email" : "email",
7496+
"slug" : "slug",
7497+
"securityUpdates" : true,
7498+
"notifications" : [ {
7499+
"slackConfiguration" : {
7500+
"webhook" : "webhook"
7501+
},
7502+
"sendOnSuccess" : false,
7503+
"sendOnFailure" : true
7504+
}, {
7505+
"slackConfiguration" : {
7506+
"webhook" : "webhook"
7507+
},
7508+
"sendOnSuccess" : false,
7509+
"sendOnFailure" : true
7510+
} ],
7511+
"workspaceId" : "046b6c7f-0b8a-43b9-b35d-6489e6daee91"
7512+
}</code></pre>
7513+
7514+
<h3 class="field-label">Produces</h3>
7515+
This API call produces the following media types according to the <span class="header">Accept</span> request header;
7516+
the media type will be conveyed by the <span class="header">Content-Type</span> response header.
7517+
<ul>
7518+
<li><code>application/json</code></li>
7519+
</ul>
7520+
7521+
<h3 class="field-label">Responses</h3>
7522+
<h4 class="field-label">200</h4>
7523+
Successful operation
7524+
<a href="#WorkspaceRead">WorkspaceRead</a>
7525+
<h4 class="field-label">404</h4>
7526+
Object with given id was not found.
7527+
<a href="#NotFoundKnownExceptionInfo">NotFoundKnownExceptionInfo</a>
7528+
<h4 class="field-label">422</h4>
7529+
Input failed validation
7530+
<a href="#InvalidInputExceptionInfo">InvalidInputExceptionInfo</a>
7531+
</div> <!-- method -->
7532+
<hr/>
74507533

74517534
<h2><a name="__Models">Models</a></h2>
74527535
[ Jump to <a href="#__Methods">Methods</a> ]
@@ -7571,6 +7654,7 @@ <h3>Table of Contents</h3>
75717654
<li><a href="#WorkspaceRead"><code>WorkspaceRead</code> - </a></li>
75727655
<li><a href="#WorkspaceReadList"><code>WorkspaceReadList</code> - </a></li>
75737656
<li><a href="#WorkspaceUpdate"><code>WorkspaceUpdate</code> - </a></li>
7657+
<li><a href="#WorkspaceUpdateName"><code>WorkspaceUpdateName</code> - </a></li>
75747658
</ol>
75757659

75767660
<div class="model">
@@ -8711,5 +8795,13 @@ <h3><a name="WorkspaceUpdate"><code>WorkspaceUpdate</code> - </a> <a class="up"
87118795
<div class="param">notifications (optional)</div><div class="param-desc"><span class="param-type"><a href="#Notification">array[Notification]</a></span> </div>
87128796
</div> <!-- field-items -->
87138797
</div>
8798+
<div class="model">
8799+
<h3><a name="WorkspaceUpdateName"><code>WorkspaceUpdateName</code> - </a> <a class="up" href="#__Models">Up</a></h3>
8800+
<div class='model-description'></div>
8801+
<div class="field-items">
8802+
<div class="param">workspaceId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
8803+
<div class="param">name </div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
8804+
</div> <!-- field-items -->
8805+
</div>
87148806
</body>
87158807
</html>

0 commit comments

Comments
 (0)