CB-2449 rm api changes for writing resources (#1066)

* CB-2449 rm api changes for writing resources

* CB-2455 feat(plugin-resource-manager): Do not rewrite script with the same name

* CB-2449 test for writing resource in rm

Co-authored-by: Konstantin Vasilev <konstantin.vasiliev@dbeaver.com>
This commit is contained in:
Ainur
2022-08-31 17:52:41 +03:00
committed by GitHub
co-authored by Konstantin Vasilev
parent 3fc7444e8c
commit 67f0853df0
14 changed files with 143 additions and 14 deletions
@@ -438,7 +438,8 @@ public class LocalResourceController implements RMController {
public String setResourceContents(
@NotNull String projectId,
@NotNull String resourcePath,
@NotNull byte[] data) throws DBException
@NotNull byte[] data,
boolean forceOverwrite) throws DBException
{
validateResourcePath(resourcePath);
Number fileSizeLimit = WebAppUtils.getWebApplication()
@@ -452,6 +453,9 @@ public class LocalResourceController implements RMController {
data.length);
}
Path targetPath = getTargetPath(projectId, resourcePath);
if (!forceOverwrite && Files.exists(targetPath)) {
throw new DBException("Resource '" + resourcePath + "' exists");
}
if (!Files.exists(targetPath.getParent())) {
throw new DBException("Parent folder '" + targetPath.getParent().getFileName() + "' doesn't exist");
}
@@ -57,7 +57,8 @@ extend type Mutation {
rmWriteResourceStringContent(
projectId: String!,
resourcePath: String!,
data: String!): String!
data: String!,
forceOverwrite: Boolean!): String!
rmCreateProject(
projectName: String!,
@@ -80,7 +80,8 @@ public interface DBWServiceRM extends DBWService {
@NotNull WebSession webSession,
@NotNull @WebObjectId String projectId,
@NotNull String resourcePath,
@NotNull String data) throws DBException;
@NotNull String data,
boolean forceOverwrite) throws DBException;
@WebAction(requirePermissions = {DBWConstants.PERMISSION_ADMIN, RMConstants.PERMISSION_RM_ADMIN})
WebProjectInfo createProject(
@@ -64,7 +64,8 @@ public class WebServiceBindingRM extends WebServiceBindingBase<DBWServiceRM> {
env -> getService(env).writeResourceStringContent(getWebSession(env),
env.getArgument("projectId"),
env.getArgument("resourcePath"),
env.getArgument("data")))
env.getArgument("data"),
env.getArgument("forceOverwrite")))
.dataFetcher("rmCreateProject", env -> getService(env).createProject(
getWebSession(env),
@@ -89,11 +89,17 @@ public class WebServiceRM implements DBWServiceRM {
@NotNull
@Override
public String writeResourceStringContent(@NotNull WebSession webSession, @NotNull String projectId, @NotNull String resourcePath, @NotNull String data) throws DBException {
public String writeResourceStringContent(
@NotNull WebSession webSession,
@NotNull String projectId,
@NotNull String resourcePath,
@NotNull String data,
boolean forceOverwrite
) throws DBException {
checkIsRmEnabled(webSession);
try {
byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
return getResourceController(webSession).setResourceContents(projectId, resourcePath, bytes);
return getResourceController(webSession).setResourceContents(projectId, resourcePath, bytes, forceOverwrite);
} catch (Exception e) {
throw new DBWebException("Error writing resource '" + resourcePath + "' data", e);
}
@@ -22,5 +22,6 @@ Require-Bundle: org.eclipse.core.runtime,
io.cloudbeaver.server,
io.cloudbeaver.resources.drivers.base,
io.cloudbeaver.product.ce,
io.cloudbeaver.service.auth
io.cloudbeaver.service.auth,
io.cloudbeaver.service.rm
Export-Package: io.cloudbeaver.test.platform
@@ -29,7 +29,7 @@ import java.net.http.HttpClient;
import java.nio.file.Path;
@RunWith(Suite.class)
@Suite.SuiteClasses({PlatformTest.class, AuthenticationTest.class })
@Suite.SuiteClasses({PlatformTest.class, AuthenticationTest.class, ResourceManagerTest.class })
public class CEServerTestSuite {
public static final String GQL_API_URL = "http://localhost:18978/api/gql";
@@ -0,0 +1,77 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2022 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 io.cloudbeaver.test.platform;
import io.cloudbeaver.model.rm.local.LocalResourceController;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.utils.WebTestUtils;
import org.jkiss.dbeaver.model.auth.SMAuthStatus;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.utils.CommonUtils;
import org.junit.Assert;
import org.junit.Test;
import java.net.CookieManager;
import java.net.http.HttpClient;
import java.util.Map;
public class ResourceManagerTest {
public static final String GQL_TEMPLATE_RM_WRITE_RESOURCE = "rmWriteResource.json";
public static final String GQL_TEMPLATE_RM_DELETE_RESOURCE = "navDeleteNode.json";
@Test
public void createDeleteResourceTest() throws Exception {
Assert.assertTrue(CBApplication.getInstance().getAppConfiguration().isResourceManagerEnabled());
HttpClient client = HttpClient.newBuilder()
.cookieHandler(new CookieManager())
.version(HttpClient.Version.HTTP_2)
.build();
Map<String, Object> authInfo = WebTestUtils.authenticateUser(
client, CEServerTestSuite.getScriptsPath(), CEServerTestSuite.GQL_API_URL);
Assert.assertEquals(SMAuthStatus.SUCCESS.name(), JSONUtils.getString(authInfo, "authStatus"));
Assert.assertTrue(createResource(client, false));
Assert.assertFalse(createResource(client, false));
Assert.assertTrue(createResource(client, true));
Assert.assertEquals(1, deleteResource(client));
}
private boolean createResource(HttpClient client, boolean forceOverwrite) throws Exception {
String input = WebTestUtils.readScriptTemplate(
GQL_TEMPLATE_RM_WRITE_RESOURCE, CEServerTestSuite.getScriptsPath()
).replaceAll("\\{forceOverwrite}", CommonUtils.toString(forceOverwrite));
Map<String, Object> map = WebTestUtils.doPost(CEServerTestSuite.GQL_API_URL, input, client);
Map<String, Object> data = JSONUtils.getObjectOrNull(map, "data");
if (data != null) {
return LocalResourceController.DEFAULT_CHANGE_ID.equals(JSONUtils.getString(data, "rmWriteResourceStringContent"));
}
return false;
}
private int deleteResource(HttpClient client) throws Exception {
String input = WebTestUtils.readScriptTemplate(GQL_TEMPLATE_RM_DELETE_RESOURCE, CEServerTestSuite.getScriptsPath());
Map<String, Object> map = WebTestUtils.doPost(CEServerTestSuite.GQL_API_URL, input, client);
Map<String, Object> data = JSONUtils.getObjectOrNull(map, "data");
if (data != null) {
return JSONUtils.getInteger(data, "navDeleteNodes");
}
return -1;
}
}
@@ -0,0 +1,9 @@
{
"query": "\n mutation navDeleteNodes($nodePaths: [ID!]!) {\n navDeleteNodes(nodePaths: $nodePaths)\n}\n ",
"variables": {
"nodePaths": [
"ext://resources/u_test/testScript.sql"
]
},
"operationName": "navDeleteNodes"
}
@@ -0,0 +1,10 @@
{
"query": "\n mutation writeContent($projectId: String!, $resourcePath: String!, $data: String!, $forceOverwrite: Boolean!) {\n rmWriteResourceStringContent(\n projectId: $projectId\n resourcePath: $resourcePath\n data: $data\n forceOverwrite: $forceOverwrite\n )\n}\n ",
"variables": {
"projectId": "u_test",
"resourcePath": "testScript.sql",
"data": "TEST SCRIPT;",
"forceOverwrite": {forceOverwrite}
},
"operationName": "writeContent"
}
@@ -1,3 +1,13 @@
mutation writeResourceContent($projectId: String!, $resourcePath: String!, $data: String!) {
rmWriteResourceStringContent(projectId: $projectId, resourcePath: $resourcePath, data: $data)
mutation writeResourceContent(
$projectId: String!,
$resourcePath: String!,
$data: String!,
$forceOverwrite: Boolean!
) {
rmWriteResourceStringContent(
projectId: $projectId,
resourcePath: $resourcePath,
data: $data,
forceOverwrite: $forceOverwrite
)
}
+4 -1
View File
@@ -563,6 +563,7 @@ export interface MutationRmMoveResourceArgs {
export interface MutationRmWriteResourceStringContentArgs {
data: Scalars['String'];
forceOverwrite: Scalars['Boolean'];
projectId: Scalars['String'];
resourcePath: Scalars['String'];
}
@@ -2446,6 +2447,7 @@ export type WriteResourceContentMutationVariables = Exact<{
projectId: Scalars['String'];
resourcePath: Scalars['String'];
data: Scalars['String'];
forceOverwrite: Scalars['Boolean'];
}>;
@@ -3907,11 +3909,12 @@ export const ReadResourceDocument = `
}
`;
export const WriteResourceContentDocument = `
mutation writeResourceContent($projectId: String!, $resourcePath: String!, $data: String!) {
mutation writeResourceContent($projectId: String!, $resourcePath: String!, $data: String!, $forceOverwrite: Boolean!) {
rmWriteResourceStringContent(
projectId: $projectId
resourcePath: $resourcePath
data: $data
forceOverwrite: $forceOverwrite
)
}
`;
@@ -40,7 +40,7 @@ export class NavResourceNodeService {
async saveScript(resourceData: IResourceData, name: string, script: string): Promise<string> {
const resourcePath = createPath(resourceData.resourcePath, name);
// await this.resourceManagerResource.createResource(resourceData.key.projectId, resourcePath, false);
await this.resourceManagerResource.writeResource(resourceData.key.projectId, resourcePath, script);
await this.resourceManagerResource.writeResource(resourceData.key.projectId, resourcePath, script, false);
await this.navTreeResource.refreshTree(resourceData.nodeId);
return createPath(RESOURCES_NODE_PATH, resourceData.key.projectId, resourcePath);
@@ -57,7 +57,12 @@ export class NavResourceNodeService {
}
async write(resourceData: IResourceData, value: string) {
await this.resourceManagerResource.writeResource(resourceData.key.projectId, resourceData.resourcePath, value);
await this.resourceManagerResource.writeResource(
resourceData.key.projectId,
resourceData.resourcePath,
value,
true
);
}
getResourceData(nodeId: string): IResourceData | undefined {
@@ -59,11 +59,12 @@ export class ResourceManagerResource extends CachedMapResource<IResourceManagerP
await this.load({ projectId, folder:folder ? resourcePath : this.getFolder(resourcePath) });
}
async writeResource(projectId: string, resourcePath: string, data: string) {
async writeResource(projectId: string, resourcePath: string, data: string, forceOverwrite: boolean) {
await this.graphQLService.sdk.writeResourceContent({
projectId,
resourcePath,
data,
forceOverwrite,
});
}