Fix #8416: Restore Entities after soft delete with all it's old data (#8635)

This commit is contained in:
Sriharsha Chintalapani 2022-11-13 10:16:01 -08:00 committed by GitHub
parent ebfb872e16
commit 9e34cb8440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 710 additions and 60 deletions

View File

@ -901,7 +901,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
return RestUtil.getHref(uriInfo, collectionPath, id);
}
public void restoreEntity(String updatedBy, String entityType, UUID id) throws IOException {
public T restoreEntity(String updatedBy, String entityType, UUID id) throws IOException {
// If an entity being restored contains other **deleted** children entities, restore them
List<EntityRelationshipRecord> records =
daoCollection.relationshipDAO().findTo(id.toString(), entityType, Relationship.CONTAINS.ordinal());
@ -919,6 +919,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
T entity = dao.findEntityById(id, DELETED);
entity.setDeleted(false);
dao.update(entity.getId(), JsonUtils.pojoToJson(entity));
return entity;
}
public void addRelationship(UUID fromId, UUID toId, String fromEntity, String toEntity, Relationship relationship) {

View File

@ -247,6 +247,14 @@ public abstract class EntityResource<T extends EntityInterface, K extends Entity
return response.toResponse();
}
public Response restoreEntity(UriInfo uriInfo, SecurityContext securityContext, UUID id) throws IOException {
OperationContext operationContext = new OperationContext(entityType, MetadataOperation.EDIT_ALL);
authorizer.authorize(securityContext, operationContext, getResourceContextById(id));
T entity = addHref(uriInfo, dao.restoreEntity(securityContext.getUserPrincipal().getName(), entityType, id));
LOG.info("Restored {}:{}", Entity.getEntityTypeFromObject(entity), entity.getId());
return Response.ok(entity.getHref()).entity(entity).build();
}
public T copy(T entity, CreateEntity request, String updatedBy) throws IOException {
EntityReference owner = dao.validateOwner(request.getOwner());
entity.setId(UUID.randomUUID());

View File

@ -37,6 +37,7 @@ import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.analytics.WebAnalyticEvent;
import org.openmetadata.schema.analytics.WebAnalyticEventData;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.tests.CreateWebAnalyticEvent;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
@ -278,6 +279,26 @@ public class WebAnalyticEventResource extends EntityResource<WebAnalyticEvent, W
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted WebAnalyticEvent.",
tags = "webAnalyticEvent",
description = "Restore a soft deleted WebAnalyticEvent.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the WebAnalyticEvent. ",
content =
@Content(mediaType = "application/json", schema = @Schema(implementation = WebAnalyticEvent.class)))
})
public Response restoreWebAnalyticEvent(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
@GET
@Path("/name/{name}")
@Operation(

View File

@ -49,6 +49,7 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.CreateBot;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.Bot;
import org.openmetadata.schema.entity.teams.User;
import org.openmetadata.schema.type.EntityHistory;
@ -350,6 +351,25 @@ public class BotResource extends EntityResource<Bot, BotRepository> {
return delete(uriInfo, securityContext, id, true, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted bot.",
tags = "bots",
description = "Restore a soft deleted bot.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Bot ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Bot.class)))
})
public Response restoreBot(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private Bot getBot(CreateBot create, String user) throws IOException {
return copy(new Bot(), create, user)
.withBotUser(create.getBotUser())

View File

@ -45,6 +45,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateChart;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Chart;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
@ -380,6 +381,25 @@ public class ChartResource extends EntityResource<Chart, ChartRepository> {
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted chart.",
tags = "charts",
description = "Restore a soft deleted chart.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Chart ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Chart.class)))
})
public Response restoreChart(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private Chart getChart(CreateChart create, String user) throws IOException {
return copy(new Chart(), create, user)
.withService(create.getService())

View File

@ -45,6 +45,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateDashboard;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Dashboard;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
@ -382,6 +383,25 @@ public class DashboardResource extends EntityResource<Dashboard, DashboardReposi
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted dashboard.",
tags = "dashboards",
description = "Restore a soft deleted dashboard.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Dashboard.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Dashboard.class)))
})
public Response restoreDashboard(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private Dashboard getDashboard(CreateDashboard create, String user) throws IOException {
return copy(new Dashboard(), create, user)
.withService(create.getService())

View File

@ -46,6 +46,7 @@ import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.dataInsight.CreateDataInsightChart;
import org.openmetadata.schema.dataInsight.DataInsightChart;
import org.openmetadata.schema.dataInsight.DataInsightChartResult;
@ -383,6 +384,26 @@ public class DataInsightChartResource extends EntityResource<DataInsightChart, D
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted DataInsightChart.",
tags = "dataInsight",
description = "Restore a soft deleted DataInsightChart.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the DataInsightChart. ",
content =
@Content(mediaType = "application/json", schema = @Schema(implementation = DataInsightChart.class)))
})
public Response restoreDataInsightChart(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
@GET
@Path("/aggregate")
@Operation(

View File

@ -45,6 +45,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateDatabase;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Database;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
@ -362,6 +363,25 @@ public class DatabaseResource extends EntityResource<Database, DatabaseRepositor
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted Database.",
tags = "tables",
description = "Restore a soft deleted Database.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Database. ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Database.class)))
})
public Response restoreDatabase(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private Database getDatabase(CreateDatabase create, String user) throws IOException {
return copy(new Database(), create, user).withService(create.getService());
}

View File

@ -45,6 +45,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateDatabaseSchema;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.DatabaseSchema;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
@ -349,6 +350,25 @@ public class DatabaseSchemaResource extends EntityResource<DatabaseSchema, Datab
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted DatabaseSchema.",
tags = "tables",
description = "Restore a soft deleted DatabaseSchema.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the DatabaseSchema ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = DatabaseSchema.class)))
})
public Response restoreDatabaseSchema(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private DatabaseSchema getDatabaseSchema(CreateDatabaseSchema create, String user) throws IOException {
return copy(new DatabaseSchema(), create, user).withDatabase(create.getDatabase());
}

View File

@ -49,6 +49,7 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateTable;
import org.openmetadata.schema.api.data.CreateTableProfile;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.tests.CreateCustomMetric;
import org.openmetadata.schema.entity.data.Table;
import org.openmetadata.schema.tests.CustomMetric;
@ -425,6 +426,25 @@ public class TableResource extends EntityResource<Table, TableRepository> {
return deleteByName(uriInfo, securityContext, fqn, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted table.",
tags = "tables",
description = "Restore a soft deleted table.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Table ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Table.class)))
})
public Response restoreTable(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
@PUT
@Path("/{id}/followers")
@Operation(

View File

@ -37,6 +37,7 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.tests.CreateTestCase;
import org.openmetadata.schema.tests.TestCase;
import org.openmetadata.schema.tests.type.TestCaseResult;
@ -425,6 +426,25 @@ public class TestCaseResource extends EntityResource<TestCase, TestCaseRepositor
return response.toResponse();
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted TestCase.",
tags = "TestCases",
description = "Restore a soft deleted TestCase.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Chart ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = TestCase.class)))
})
public Response restoreTestCase(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
@PUT
@Path("/{fqn}/testCaseResult")
@Operation(

View File

@ -34,6 +34,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.tests.CreateTestDefinition;
import org.openmetadata.schema.tests.TestDefinition;
import org.openmetadata.schema.tests.TestPlatform;
@ -368,6 +369,25 @@ public class TestDefinitionResource extends EntityResource<TestDefinition, TestD
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted TestDefinition.",
tags = "TestDefinitions",
description = "Restore a soft deleted TestDefinition.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the TestDefinition. ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = TestDefinition.class)))
})
public Response restoreTestDefinition(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private TestDefinition getTestDefinition(CreateTestDefinition create, String user) throws IOException {
return copy(new TestDefinition(), create, user)
.withDescription(create.getDescription())

View File

@ -33,6 +33,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.tests.CreateTestSuite;
import org.openmetadata.schema.tests.TestSuite;
import org.openmetadata.schema.type.EntityHistory;
@ -333,6 +334,25 @@ public class TestSuiteResource extends EntityResource<TestSuite, TestSuiteReposi
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted TestSuite.",
tags = "TestSuites",
description = "Restore a soft deleted TestSuite.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the TestSuite.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = TestSuite.class)))
})
public Response restoreTestSuite(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private TestSuite getTestSuite(CreateTestSuite create, String user) throws IOException {
return copy(new TestSuite(), create, user)
.withDescription(create.getDescription())

View File

@ -46,6 +46,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateGlossary;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Glossary;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
@ -345,6 +346,25 @@ public class GlossaryResource extends EntityResource<Glossary, GlossaryRepositor
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted Glossary.",
tags = "glossaries",
description = "Restore a soft deleted Glossary.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Glossary ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Glossary.class)))
})
public Response restoreGlossary(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private Glossary getGlossary(CreateGlossary create, String user) throws IOException {
return copy(new Glossary(), create, user)
.withReviewers(create.getReviewers())

View File

@ -46,6 +46,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateGlossaryTerm;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Glossary;
import org.openmetadata.schema.entity.data.GlossaryTerm;
import org.openmetadata.schema.type.EntityHistory;
@ -394,6 +395,25 @@ public class GlossaryTermResource extends EntityResource<GlossaryTerm, GlossaryT
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted GlossaryTerm.",
tags = "glossaryTerm",
description = "Restore a soft deleted GlossaryTerm.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Chart ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = GlossaryTerm.class)))
})
public Response restoreTable(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private GlossaryTerm getGlossaryTerm(CreateGlossaryTerm create, String user) throws IOException {
return copy(new GlossaryTerm(), create, user)
.withSynonyms(create.getSynonyms())

View File

@ -35,6 +35,7 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.dataInsight.kpi.CreateKpiRequest;
import org.openmetadata.schema.dataInsight.kpi.Kpi;
import org.openmetadata.schema.dataInsight.type.KpiResult;
@ -341,6 +342,25 @@ public class KpiResource extends EntityResource<Kpi, KpiRepository> {
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted Kpi.",
tags = "kpi",
description = "Restore a soft deleted Kpi.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Kpi. ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Kpi.class)))
})
public Response restoreKpi(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
@PUT
@Path("/{fqn}/kpiResult")
@Operation(

View File

@ -46,6 +46,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateLocation;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Location;
import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
@ -425,6 +426,25 @@ public class LocationResource extends EntityResource<Location, LocationRepositor
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted location.",
tags = "locations",
description = "Restore a soft deleted location.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Location ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Location.class)))
})
public Response restoreLocation(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
@PUT
@Path("/{id}/followers")
@Operation(

View File

@ -45,6 +45,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateMlModel;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.MlModel;
import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
@ -396,6 +397,25 @@ public class MlModelResource extends EntityResource<MlModel, MlModelRepository>
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted MlModel.",
tags = "mlModels",
description = "Restore a soft deleted MlModel.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the MlModel ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = MlModel.class)))
})
public Response restoreMlModel(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private MlModel getMlModel(CreateMlModel create, String user) throws IOException {
return copy(new MlModel(), create, user)
.withService(create.getService())

View File

@ -46,6 +46,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreatePipeline;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Pipeline;
import org.openmetadata.schema.entity.data.PipelineStatus;
import org.openmetadata.schema.type.ChangeEvent;
@ -497,6 +498,25 @@ public class PipelineResource extends EntityResource<Pipeline, PipelineRepositor
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted Pipeline.",
tags = "pipelines",
description = "Restore a soft deleted Pipeline.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Pipeline ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Pipeline.class)))
})
public Response restorePipeline(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private Pipeline getPipeline(CreatePipeline create, String user) throws IOException {
return copy(new Pipeline(), create, user)
.withService(create.getService())

View File

@ -49,6 +49,7 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.common.utils.CommonUtil;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.policies.CreatePolicy;
import org.openmetadata.schema.entity.policies.Policy;
import org.openmetadata.schema.type.EntityHistory;
@ -419,6 +420,25 @@ public class PolicyResource extends EntityResource<Policy, PolicyRepository> {
return response;
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted policy.",
tags = "policies",
description = "Restore a soft deleted policy.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Policy ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Policy.class)))
})
public Response restorePolicy(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
@GET
@Path("/validation/condition/{expression}")
@Operation(

View File

@ -43,6 +43,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.services.CreateDashboardService;
import org.openmetadata.schema.entity.services.DashboardService;
import org.openmetadata.schema.entity.services.ServiceType;
@ -344,6 +345,26 @@ public class DashboardServiceResource
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted DashboardService.",
tags = "dashboardServices",
description = "Restore a soft deleted DashboardService.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Chart ",
content =
@Content(mediaType = "application/json", schema = @Schema(implementation = DashboardService.class)))
})
public Response restoreDashboardService(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private DashboardService getService(CreateDashboardService create, String user) throws IOException {
return copy(new DashboardService(), create, user)
.withServiceType(create.getServiceType())

View File

@ -42,6 +42,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.services.CreateDatabaseService;
import org.openmetadata.schema.api.services.DatabaseConnection;
import org.openmetadata.schema.entity.services.DatabaseService;
@ -92,7 +93,7 @@ public class DatabaseServiceResource
@Operation(
operationId = "listDatabaseServices",
summary = "List database services",
tags = "databaseService",
tags = "databaseServices",
description = "Get a list of database services.",
responses = {
@ApiResponse(
@ -143,7 +144,7 @@ public class DatabaseServiceResource
@Operation(
operationId = "getDatabaseServiceByID",
summary = "Get a database service",
tags = "databaseService",
tags = "databaseServices",
description = "Get a database service by `id`.",
responses = {
@ApiResponse(
@ -178,7 +179,7 @@ public class DatabaseServiceResource
@Operation(
operationId = "getDatabaseServiceByFQN",
summary = "Get database service by name",
tags = "databaseService",
tags = "databaseServices",
description = "Get a database service by the service `name`.",
responses = {
@ApiResponse(
@ -213,7 +214,7 @@ public class DatabaseServiceResource
@Operation(
operationId = "listAllDatabaseServiceVersion",
summary = "List database service versions",
tags = "databaseService",
tags = "databaseServices",
description = "Get a list of all the versions of a database service identified by `id`",
responses = {
@ApiResponse(
@ -249,7 +250,7 @@ public class DatabaseServiceResource
@Operation(
operationId = "getSpecificDatabaseServiceVersion",
summary = "Get a version of the database service",
tags = "databaseService",
tags = "databaseServices",
description = "Get a version of the database service by given `id`",
responses = {
@ApiResponse(
@ -279,7 +280,7 @@ public class DatabaseServiceResource
@Operation(
operationId = "createDatabaseService",
summary = "Create database service",
tags = "databaseService",
tags = "databaseServices",
description = "Create a new database service.",
responses = {
@ApiResponse(
@ -302,7 +303,7 @@ public class DatabaseServiceResource
@Operation(
operationId = "createOrUpdateDatabaseService",
summary = "Update database service",
tags = "databaseService",
tags = "databaseServices",
description = "Update an existing or create a new database service.",
responses = {
@ApiResponse(
@ -326,7 +327,7 @@ public class DatabaseServiceResource
@Operation(
operationId = "deleteDatabaseService",
summary = "Delete a database service",
tags = "databaseService",
tags = "databaseServices",
description =
"Delete a database services. If databases (and tables) belong the service, it can't be " + "deleted.",
responses = {
@ -350,6 +351,26 @@ public class DatabaseServiceResource
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted DatabaseService.",
tags = "databaseServices",
description = "Restore a soft deleted DatabaseService.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the DatabaseService.",
content =
@Content(mediaType = "application/json", schema = @Schema(implementation = DatabaseService.class)))
})
public Response restoreDatabaseService(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private DatabaseService getService(CreateDatabaseService create, String user) throws IOException {
return copy(new DatabaseService(), create, user)
.withServiceType(create.getServiceType())

View File

@ -52,6 +52,7 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.services.ingestionPipelines.CreateIngestionPipeline;
import org.openmetadata.schema.api.services.ingestionPipelines.TestServiceConnection;
import org.openmetadata.schema.entity.services.ingestionPipelines.IngestionPipeline;
@ -120,7 +121,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "listIngestionPipelines",
summary = "List Ingestion Pipelines for Metadata Operations",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description =
"Get a list of Airflow Pipelines for Metadata Operations. Use `fields` parameter to get only necessary fields. "
+ " Use cursor-based pagination to limit the number "
@ -182,7 +183,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "listAllIngestionPipelineVersion",
summary = "List ingestion workflow versions",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Get a list of all the versions of a IngestionPipeline identified by `id`",
responses = {
@ApiResponse(
@ -203,7 +204,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "getIngestionPipelineByID",
summary = "Get a IngestionPipeline",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Get a IngestionPipeline by `id`.",
responses = {
@ApiResponse(
@ -241,7 +242,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "getSpecificIngestionPipelineVersion",
summary = "Get a version of the IngestionPipeline",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Get a version of the IngestionPipeline by given `id`",
responses = {
@ApiResponse(
@ -271,7 +272,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "getSpecificIngestionPipelineByFQN",
summary = "Get a IngestionPipeline by name",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Get a ingestion by fully qualified name.",
responses = {
@ApiResponse(
@ -308,7 +309,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "createIngestionPipeline",
summary = "Create a Ingestion Pipeline",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Create a new Ingestion Pipeline.",
responses = {
@ApiResponse(
@ -332,7 +333,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "patchIngestionPipeline",
summary = "Update a IngestionPipeline",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Update an existing IngestionPipeline using JsonPatch.",
externalDocs = @ExternalDocumentation(description = "JsonPatch RFC", url = "https://tools.ietf.org/html/rfc6902"))
@Consumes(MediaType.APPLICATION_JSON_PATCH_JSON)
@ -359,7 +360,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "createOrUpdateIngestionPipeline",
summary = "Create or update a IngestionPipeline",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Create a new IngestionPipeline, if it does not exist or update an existing IngestionPipeline.",
responses = {
@ApiResponse(
@ -382,7 +383,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Path("/deploy/{id}")
@Operation(
summary = "Deploy a ingestion pipeline run",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Trigger a ingestion pipeline run by id.",
responses = {
@ApiResponse(
@ -409,7 +410,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "triggerIngestionPipelineRun",
summary = "Trigger a ingestion pipeline run",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Trigger a ingestion pipeline run by id.",
responses = {
@ApiResponse(
@ -433,7 +434,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "toggleIngestionPipelineEnabled",
summary = "Set an Ingestion pipeline either as Enabled or Disabled",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Toggle an ingestion pipeline state by id.",
responses = {
@ApiResponse(
@ -457,7 +458,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "killIngestionPipelineRuns",
summary = "Mark as failed and kill any not-finished workflow or task for the IngestionPipeline",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Kill an ingestion pipeline by ID.",
responses = {
@ApiResponse(
@ -480,7 +481,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "testConnection",
summary = "Test Connection of a Service",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Test Connection of a Service.",
responses = {
@ApiResponse(
@ -504,7 +505,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "checkAirflowHostIp",
summary = "Check the Airflow REST host IP",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Check the Airflow REST host IP",
responses = {
@ApiResponse(
@ -522,7 +523,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "checkRestAirflowStatus",
summary = "Check the Airflow REST status",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Check that the Airflow REST endpoint is reachable and up and running",
responses = {
@ApiResponse(
@ -539,7 +540,7 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
@Operation(
operationId = "deleteIngestionPipeline",
summary = "Delete a Ingestion",
tags = "IngestionPipelines",
tags = "ingestionPipelines",
description = "Delete a ingestion by `id`.",
responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ -557,6 +558,26 @@ public class IngestionPipelineResource extends EntityResource<IngestionPipeline,
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted IngestionPipeline.",
tags = "ingestionPipelines",
description = "Restore a soft deleted IngestionPipeline.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the IngestionPipeline. ",
content =
@Content(mediaType = "application/json", schema = @Schema(implementation = IngestionPipeline.class)))
})
public Response restoreIngestionPipeline(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
@GET
@Path("/logs/{id}/last")
@Operation(

View File

@ -43,6 +43,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.services.CreateMessagingService;
import org.openmetadata.schema.entity.services.MessagingService;
import org.openmetadata.schema.entity.services.ServiceType;
@ -91,7 +92,7 @@ public class MessagingServiceResource
@Operation(
operationId = "listMessagingService",
summary = "List messaging services",
tags = "MessagingService",
tags = "messagingServices",
description =
"Get a list of messaging services. Use cursor-based pagination to limit the number "
+ "entries in the list using `limit` and `before` or `after` query params.",
@ -140,7 +141,7 @@ public class MessagingServiceResource
@Operation(
operationId = "getMessagingServiceByID",
summary = "Get a messaging service",
tags = "MessagingService",
tags = "messagingServices",
description = "Get a messaging service by `id`.",
responses = {
@ApiResponse(
@ -175,7 +176,7 @@ public class MessagingServiceResource
@Operation(
operationId = "getMessagingServiceByFQN",
summary = "Get messaging service by name",
tags = "MessagingService",
tags = "messagingServices",
description = "Get a messaging service by the service `name`.",
responses = {
@ApiResponse(
@ -210,7 +211,7 @@ public class MessagingServiceResource
@Operation(
operationId = "listAllMessagingServiceVersion",
summary = "List messaging service versions",
tags = "MessagingService",
tags = "messagingServices",
description = "Get a list of all the versions of a messaging service identified by `id`",
responses = {
@ApiResponse(
@ -246,7 +247,7 @@ public class MessagingServiceResource
@Operation(
operationId = "getSpecificMessagingServiceVersion",
summary = "Get a version of the messaging service",
tags = "MessagingService",
tags = "messagingServices",
description = "Get a version of the messaging service by given `id`",
responses = {
@ApiResponse(
@ -276,7 +277,7 @@ public class MessagingServiceResource
@Operation(
operationId = "createMessagingService",
summary = "Create a messaging service",
tags = "MessagingService",
tags = "messagingService",
description = "Create a new messaging service.",
responses = {
@ApiResponse(
@ -299,7 +300,7 @@ public class MessagingServiceResource
@Operation(
operationId = "createOrUpdateMessagingService",
summary = "Update messaging service",
tags = "MessagingService",
tags = "messagingServices",
description = "Create a new messaging service or Update an existing messaging service identified by `id`.",
responses = {
@ApiResponse(
@ -323,7 +324,7 @@ public class MessagingServiceResource
@Operation(
operationId = "deleteMessagingService",
summary = "Delete a messaging service",
tags = "MessagingService",
tags = "messagingServices",
description = "Delete a messaging service. If topics belong the service, it can't be " + "deleted.",
responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ -345,6 +346,26 @@ public class MessagingServiceResource
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted MessagingService.",
tags = "messagingServices",
description = "Restore a soft deleted MessagingService.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the MessagingService ",
content =
@Content(mediaType = "application/json", schema = @Schema(implementation = MessagingService.class)))
})
public Response restoreMessagingService(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private MessagingService getService(CreateMessagingService create, String user) throws IOException {
return copy(new MessagingService(), create, user)
.withConnection(create.getConnection())

View File

@ -41,6 +41,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.services.CreateMlModelService;
import org.openmetadata.schema.entity.services.MlModelService;
import org.openmetadata.schema.entity.services.ServiceType;
@ -90,7 +91,7 @@ public class MlModelServiceResource
@Operation(
operationId = "listMlModelService",
summary = "List mlModel services",
tags = "mlModelService",
tags = "mlModelServices",
description =
"Get a list of mlModel services. Use cursor-based pagination to limit the number "
+ "entries in the list using `limit` and `before` or `after` query params.",
@ -139,7 +140,7 @@ public class MlModelServiceResource
@Operation(
operationId = "getMlModelServiceByID",
summary = "Get a mlModel service",
tags = "mlModelService",
tags = "mlModelServices",
description = "Get a mlModel service by `id`.",
responses = {
@ApiResponse(
@ -174,7 +175,7 @@ public class MlModelServiceResource
@Operation(
operationId = "getMlModelServiceByFQN",
summary = "Get mlModel service by name",
tags = "mlModelService",
tags = "mlModelServices",
description = "Get a mlModel service by the service `name`.",
responses = {
@ApiResponse(
@ -209,7 +210,7 @@ public class MlModelServiceResource
@Operation(
operationId = "listAllMlModelServiceVersion",
summary = "List mlModel service versions",
tags = "mlModelService",
tags = "mlModelServices",
description = "Get a list of all the versions of a mlModel service identified by `id`",
responses = {
@ApiResponse(
@ -245,7 +246,7 @@ public class MlModelServiceResource
@Operation(
operationId = "getSpecificMlModelService",
summary = "Get a version of the mlModel service",
tags = "mlModelService",
tags = "mlModelServices",
description = "Get a version of the mlModel service by given `id`",
responses = {
@ApiResponse(
@ -298,7 +299,7 @@ public class MlModelServiceResource
@Operation(
operationId = "createOrUpdateMlModelService",
summary = "Update mlModel service",
tags = "mlModelService",
tags = "mlModelServices",
description = "Create a new mlModel service or update an existing mlModel service identified by `id`.",
responses = {
@ApiResponse(
@ -322,7 +323,7 @@ public class MlModelServiceResource
@Operation(
operationId = "deleteMlModelService",
summary = "Delete a mlModel service",
tags = "mlModelService",
tags = "mlModelServices",
description =
"Delete a mlModel services. If mlModels (and tasks) belong to the service, it can't be " + "deleted.",
responses = {
@ -345,6 +346,25 @@ public class MlModelServiceResource
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted MlModelService.",
tags = "mlModelServices",
description = "Restore a soft deleted MlModelService.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the MlModelService ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = MlModelService.class)))
})
public Response restoreTable(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private MlModelService getService(CreateMlModelService create, String user) throws IOException {
return copy(new MlModelService(), create, user)
.withServiceType(create.getServiceType())

View File

@ -41,6 +41,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.services.CreatePipelineService;
import org.openmetadata.schema.entity.services.PipelineService;
import org.openmetadata.schema.entity.services.ServiceType;
@ -89,7 +90,7 @@ public class PipelineServiceResource
@Operation(
operationId = "listPipelineService",
summary = "List pipeline services",
tags = "pipelineService",
tags = "pipelineServices",
description =
"Get a list of pipeline services. Use cursor-based pagination to limit the number "
+ "entries in the list using `limit` and `before` or `after` query params.",
@ -138,7 +139,7 @@ public class PipelineServiceResource
@Operation(
operationId = "getPipelineServiceByID",
summary = "Get a pipeline service",
tags = "pipelineService",
tags = "pipelineServices",
description = "Get a pipeline service by `id`.",
responses = {
@ApiResponse(
@ -173,7 +174,7 @@ public class PipelineServiceResource
@Operation(
operationId = "getPipelineServiceByFQN",
summary = "Get pipeline service by name",
tags = "pipelineService",
tags = "pipelineServices",
description = "Get a pipeline service by the service `name`.",
responses = {
@ApiResponse(
@ -208,7 +209,7 @@ public class PipelineServiceResource
@Operation(
operationId = "listAllPipelineServiceVersion",
summary = "List pipeline service versions",
tags = "pipelineService",
tags = "pipelineServices",
description = "Get a list of all the versions of a pipeline service identified by `id`",
responses = {
@ApiResponse(
@ -244,7 +245,7 @@ public class PipelineServiceResource
@Operation(
operationId = "getSpecificPipelineService",
summary = "Get a version of the pipeline service",
tags = "pipelineService",
tags = "pipelineServices",
description = "Get a version of the pipeline service by given `id`",
responses = {
@ApiResponse(
@ -274,7 +275,7 @@ public class PipelineServiceResource
@Operation(
operationId = "createPipelineService",
summary = "Create a pipeline service",
tags = "pipelineService",
tags = "pipelineServices",
description = "Create a new pipeline service.",
responses = {
@ApiResponse(
@ -297,7 +298,7 @@ public class PipelineServiceResource
@Operation(
operationId = "createOrUpdatePipelineService",
summary = "Update pipeline service",
tags = "pipelineService",
tags = "pipelineServices",
description = "Create a new pipeline service or update an existing pipeline service identified by `id`.",
responses = {
@ApiResponse(
@ -321,7 +322,7 @@ public class PipelineServiceResource
@Operation(
operationId = "deletePipelineService",
summary = "Delete a pipeline service",
tags = "pipelineService",
tags = "pipelineServices",
description =
"Delete a pipeline services. If pipelines (and tasks) belong to the service, it can't be " + "deleted.",
responses = {
@ -345,6 +346,26 @@ public class PipelineServiceResource
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted PipelineService.",
tags = "pipelineServices",
description = "Restore a soft deleted PipelineService.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the PipelineService ",
content =
@Content(mediaType = "application/json", schema = @Schema(implementation = PipelineService.class)))
})
public Response restorePipelineService(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private PipelineService getService(CreatePipelineService create, String user) throws IOException {
return copy(new PipelineService(), create, user)
.withServiceType(create.getServiceType())

View File

@ -41,6 +41,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.services.CreateStorageService;
import org.openmetadata.schema.entity.services.StorageService;
import org.openmetadata.schema.type.EntityHistory;
@ -85,7 +86,7 @@ public class StorageServiceResource extends EntityResource<StorageService, Stora
@Operation(
operationId = "listStorageService",
summary = "List storage services",
tags = "storageService",
tags = "storageServices",
description =
"Get a list of storage services. Use cursor-based pagination to limit the number "
+ "entries in the list using `limit` and `before` or `after` query params.",
@ -132,7 +133,7 @@ public class StorageServiceResource extends EntityResource<StorageService, Stora
@Operation(
operationId = "getStorageServiceByID",
summary = "Get a storage service",
tags = "storageService",
tags = "storageServices",
description = "Get a storage service by `id`.",
responses = {
@ApiResponse(
@ -166,7 +167,7 @@ public class StorageServiceResource extends EntityResource<StorageService, Stora
@Operation(
operationId = "getStorageServiceByFQN",
summary = "Get storage service by name",
tags = "storageService",
tags = "storageServices",
description = "Get a storage service by the service `name`.",
responses = {
@ApiResponse(
@ -200,7 +201,7 @@ public class StorageServiceResource extends EntityResource<StorageService, Stora
@Operation(
operationId = "listAllStorageServiceVersion",
summary = "List storage service versions",
tags = "storageService",
tags = "storageServices",
description = "Get a list of all the versions of a storage service identified by `id`",
responses = {
@ApiResponse(
@ -221,7 +222,7 @@ public class StorageServiceResource extends EntityResource<StorageService, Stora
@Operation(
operationId = "getSpecificStorageServiceVersion",
summary = "Get a version of the storage service",
tags = "storageService",
tags = "storageServices",
description = "Get a version of the storage service by given `id`",
responses = {
@ApiResponse(
@ -250,7 +251,7 @@ public class StorageServiceResource extends EntityResource<StorageService, Stora
@Operation(
operationId = "createStorageService",
summary = "Create storage service",
tags = "storageService",
tags = "storageServices",
description = "Create a new storage service.",
responses = {
@ApiResponse(
@ -271,7 +272,7 @@ public class StorageServiceResource extends EntityResource<StorageService, Stora
@Operation(
operationId = "createOrUpdateStorageService",
summary = "Update storage service",
tags = "storageService",
tags = "storageServices",
description = "Update an existing storage service identified by `id`.",
responses = {
@ApiResponse(
@ -293,7 +294,7 @@ public class StorageServiceResource extends EntityResource<StorageService, Stora
@Operation(
operationId = "deleteStorageService",
summary = "Delete a storage service",
tags = "storageService",
tags = "storageServices",
description = "Delete a storage services. If storages (and tables) belong the service, it can't be " + "deleted.",
responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ -315,6 +316,25 @@ public class StorageServiceResource extends EntityResource<StorageService, Stora
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted StorageService.",
tags = "storageServices",
description = "Restore a soft deleted StorageService.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the StorageService ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = StorageService.class)))
})
public Response restoreTable(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private StorageService getService(CreateStorageService create, String user) throws IOException {
return copy(new StorageService(), create, user).withServiceType(create.getServiceType());
}

View File

@ -49,6 +49,7 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.EntityInterface;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.teams.CreateRole;
import org.openmetadata.schema.entity.teams.Role;
import org.openmetadata.schema.type.EntityHistory;
@ -383,6 +384,25 @@ public class RoleResource extends EntityResource<Role, RoleRepository> {
return response;
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted role.",
tags = "roles",
description = "Restore a soft deleted role.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Role. ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Role.class)))
})
public Response restoreRole(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private Role getRole(CreateRole create, String user) throws IOException {
if (nullOrEmpty(create.getPolicies())) {
throw new IllegalArgumentException("At least one policy is required to create a role");

View File

@ -48,6 +48,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.teams.CreateTeam;
import org.openmetadata.schema.api.teams.CreateTeam.TeamType;
import org.openmetadata.schema.entity.teams.Team;
@ -408,6 +409,25 @@ public class TeamResource extends EntityResource<Team, TeamRepository> {
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted Team.",
tags = "teams",
description = "Restore a soft deleted Team.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Team ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Team.class)))
})
public Response restoreTeam(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private Team getTeam(CreateTeam ct, String user) throws IOException {
if (ct.getTeamType().equals(TeamType.ORGANIZATION)) {
throw new IllegalArgumentException(CREATE_ORGANIZATION);

View File

@ -67,6 +67,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.openmetadata.schema.EntityInterface;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.security.AuthenticationConfiguration;
import org.openmetadata.schema.api.teams.CreateUser;
import org.openmetadata.schema.auth.ChangePasswordRequest;
@ -743,6 +744,25 @@ public class UserResource extends EntityResource<User, UserRepository> {
return response;
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted User.",
tags = "users",
description = "Restore a soft deleted User.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the User ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = User.class)))
})
public Response restoreTable(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
@POST
@Path("/signup")
@Operation(

View File

@ -46,6 +46,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.openmetadata.schema.api.data.CreateTopic;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Topic;
import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
@ -418,6 +419,25 @@ public class TopicResource extends EntityResource<Topic, TopicRepository> {
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/restore")
@Operation(
operationId = "restore",
summary = "Restore a soft deleted topic.",
tags = "topics",
description = "Restore a soft deleted topic.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Successfully restored the Topic. ",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Topic.class)))
})
public Response restoreTopic(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid RestoreEntity restore)
throws IOException {
return restoreEntity(uriInfo, securityContext, restore.getId());
}
private Topic getTopic(CreateTopic create, String user) throws IOException {
return copy(new Topic(), create, user)
.withService(create.getService())

View File

@ -98,6 +98,7 @@ import org.junit.jupiter.api.TestInstance;
import org.openmetadata.common.utils.CommonUtil;
import org.openmetadata.schema.CreateEntity;
import org.openmetadata.schema.EntityInterface;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.api.data.TermReference;
import org.openmetadata.schema.api.teams.CreateTeam;
import org.openmetadata.schema.api.teams.CreateTeam.TeamType;
@ -1439,9 +1440,9 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
permissionNotAllowed(TEST_USER_NAME, List.of(MetadataOperation.DELETE)));
}
/** Soft delete an entity and then use PUT request to restore it back */
// @Test
void delete_put_entity_200(TestInfo test) throws IOException {
/** Soft delete an entity and then use restore request to restore it back */
@Test
void delete_restore_entity_200(TestInfo test) throws IOException {
K request = createRequest(getEntityName(test), "", "", null);
T entity = createEntity(request, ADMIN_AUTH_HEADERS);
@ -1454,7 +1455,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
// Send PUT request (with no changes) to restore the entity from soft deleted state
ChangeDescription change = getChangeDescription(version);
fieldUpdated(change, FIELD_DELETED, true, false);
updateAndCheckEntity(request, Response.Status.OK, ADMIN_AUTH_HEADERS, MINOR_UPDATE, change);
restoreAndCheckEntity(entity, Response.Status.OK, ADMIN_AUTH_HEADERS, NO_CHANGE, change);
} else {
assertEntityDeleted(entity, true);
}
@ -1560,6 +1561,10 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
return getCollection().path("/name/" + name);
}
protected final WebTarget getRestoreResource(UUID id) {
return getCollection().path("/restore");
}
protected final WebTarget getFollowersCollection(UUID id) {
return getResource(collectionName + "/" + id + "/followers");
}
@ -1669,6 +1674,12 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
return entity;
}
public final T restoreEntity(RestoreEntity restore, Status status, Map<String, String> authHeaders)
throws HttpResponseException {
WebTarget target = getRestoreResource(restore.getId());
return TestUtils.put(target, restore, entityClass, status, authHeaders);
}
/** Helper function to create an entity, submit POST API request and validate response. */
public final T createAndCheckEntity(K create, Map<String, String> authHeaders) throws IOException {
// Validate an entity that is created has all the information set in create request
@ -1723,6 +1734,27 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
return updated;
}
protected final T restoreAndCheckEntity(
T entity,
Status status,
Map<String, String> authHeaders,
UpdateType updateType,
ChangeDescription changeDescription)
throws IOException {
T updated = restoreEntity(new RestoreEntity().withId(entity.getId()), status, authHeaders);
validateLatestVersion(updated, updateType, changeDescription, authHeaders);
// GET the newly updated entity and validate
T getEntity = getEntity(updated.getId(), authHeaders);
validateChangeDescription(getEntity, updateType, changeDescription);
// Check if the entity change events are record
if (updateType != NO_CHANGE) {
EventType expectedEventType =
updateType == UpdateType.CREATED ? EventType.ENTITY_CREATED : EventType.ENTITY_UPDATED;
validateChangeEvents(updated, updated.getUpdatedAt(), expectedEventType, changeDescription, authHeaders);
}
return updated;
}
protected void validateEntityHistory(
UUID id, UpdateType updateType, ChangeDescription expectedChangeDescription, Map<String, String> authHeaders)
throws IOException {

View File

@ -323,6 +323,12 @@ public final class TestUtils {
return readResponse(response, clz, Status.OK.getStatusCode());
}
public static <T> T put(WebTarget target, Class<T> clz, Status expectedStatus, Map<String, String> headers)
throws HttpResponseException {
Response response = SecurityUtil.addHeaders(target, headers).method("PUT");
return readResponse(response, clz, expectedStatus.getStatusCode());
}
public static <K> void put(WebTarget target, K request, Status expectedStatus, Map<String, String> headers)
throws HttpResponseException {
Response response =

View File

@ -0,0 +1,16 @@
{
"$id": "https://open-metadata.org/schema/api/restoreEntity.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "restoreEntity",
"description": "Restore Entity API request to restore soft deleted entity.",
"type": "object",
"javaType": "org.openmetadata.schema.api.data.RestoreEntity",
"properties": {
"id": {
"description": "Unique identifier that identifies an entity instance.",
"$ref": "../../type/basic.json#/definitions/uuid"
}
},
"required": ["id"],
"additionalProperties": false
}