Add Voting to Entities (#13101)

* Add Voting to Entities

* Fix Failing test and maven build failure in main

* revert files
This commit is contained in:
Mohit Yadav 2023-09-08 16:23:32 +05:30 committed by GitHub
parent cc5128fcb3
commit e70f7afe4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 383 additions and 12 deletions

View File

@ -244,6 +244,10 @@ public abstract class EntityRepository<T extends EntityInterface> {
this.putFields.addField(allowedFields, FIELD_EXTENSION);
}
this.supportsVotes = allowedFields.contains(FIELD_VOTES);
if (supportsVotes) {
this.patchFields.addField(allowedFields, FIELD_VOTES);
this.putFields.addField(allowedFields, FIELD_VOTES);
}
this.supportsDomain = allowedFields.contains(FIELD_DOMAIN);
if (supportsDomain) {
this.patchFields.addField(allowedFields, FIELD_DOMAIN);
@ -670,6 +674,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
entity.setChildren(fields.contains(FIELD_CHILDREN) ? getChildren(entity) : entity.getChildren());
entity.setExperts(fields.contains(FIELD_EXPERTS) ? getExperts(entity) : entity.getExperts());
entity.setReviewers(fields.contains(FIELD_REVIEWERS) ? getReviewers(entity) : entity.getReviewers());
entity.setVotes(fields.contains(FIELD_VOTES) ? getVotes(entity) : entity.getVotes());
setFields(entity, fields);
return entity;
}
@ -684,6 +689,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
entity.setChildren(fields.contains(FIELD_CHILDREN) ? entity.getChildren() : null);
entity.setExperts(fields.contains(FIELD_EXPERTS) ? entity.getExperts() : null);
entity.setReviewers(fields.contains(FIELD_REVIEWERS) ? entity.getReviewers() : null);
entity.setVotes(fields.contains(FIELD_VOTES) ? entity.getVotes() : null);
clearFields(entity, fields);
return entity;
}

View File

@ -27,10 +27,9 @@ import org.openmetadata.service.util.RestUtil;
public class QueryRepository extends EntityRepository<Query> {
private static final String QUERY_USED_IN_FIELD = "queryUsedIn";
private static final String QUERY_USERS_FIELD = "users";
private static final String QUERY_PATCH_FIELDS = "users,query,queryUsedIn";
private static final String QUERY_UPDATE_FIELDS = "users,votes,queryUsedIn";
private static final String QUERY_UPDATE_FIELDS = "users,queryUsedIn";
public QueryRepository(CollectionDAO dao) {
super(
@ -45,14 +44,12 @@ public class QueryRepository extends EntityRepository<Query> {
@Override
public Query setFields(Query entity, EntityUtil.Fields fields) {
entity.setVotes(fields.contains("votes") ? getVotes(entity) : entity.getVotes());
entity.setQueryUsedIn(fields.contains(QUERY_USED_IN_FIELD) ? getQueryUsage(entity) : entity.getQueryUsedIn());
return entity.withUsers(fields.contains("users") ? getQueryUsers(entity) : entity.getUsers());
}
@Override
public Query clearFields(Query entity, EntityUtil.Fields fields) {
entity.withVotes(fields.contains("votes") ? entity.getVotes() : null);
entity.withQueryUsedIn(fields.contains(QUERY_USED_IN_FIELD) ? entity.getQueryUsedIn() : null);
return entity.withUsers(fields.contains("users") ? this.getQueryUsers(entity) : null);
}

View File

@ -59,7 +59,7 @@ public abstract class EntityResource<T extends EntityInterface, K extends Entity
allowedFields = repository.getAllowedFields();
this.repository = repository;
this.authorizer = authorizer;
addViewOperation("owner,followers,tags,extension", VIEW_BASIC);
addViewOperation("owner,followers,votes,tags,extension", VIEW_BASIC);
Entity.registerEntity(entityClass, entityType, repository, getEntitySpecificOperations());
}
@ -344,7 +344,7 @@ public abstract class EntityResource<T extends EntityInterface, K extends Entity
for (String field : fields) {
if (allowedFields.contains(field)) {
fieldsToViewOperations.put(field, operation);
} else if (!"owner,followers,tags,extension".contains(field)) {
} else if (!"owner,followers,votes,tags,extension".contains(field)) {
// Some common fields for all the entities might be missing. Ignore it.
throw new IllegalArgumentException(CatalogExceptionMessage.invalidField(field));
}

View File

@ -46,9 +46,11 @@ 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.VoteRequest;
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.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
@ -386,6 +388,27 @@ public class ChartResource extends EntityResource<Chart, ChartRepository> {
return deleteByName(uriInfo, securityContext, fqn, false, hardDelete);
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@PUT
@Path("/restore")
@Operation(

View File

@ -46,9 +46,11 @@ 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.VoteRequest;
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.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
@ -353,6 +355,27 @@ public class DashboardResource extends EntityResource<Dashboard, DashboardReposi
return repository.deleteFollower(securityContext.getUserPrincipal().getName(), id, userId).toResponse();
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/{id}")
@Operation(

View File

@ -46,9 +46,11 @@ 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.VoteRequest;
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.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
@ -339,6 +341,27 @@ public class DatabaseResource extends EntityResource<Database, DatabaseRepositor
return delete(uriInfo, securityContext, id, recursive, hardDelete);
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/name/{fqn}")
@Operation(

View File

@ -46,9 +46,11 @@ 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.VoteRequest;
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.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
@ -319,6 +321,27 @@ public class DatabaseSchemaResource extends EntityResource<DatabaseSchema, Datab
return createOrUpdate(uriInfo, securityContext, schema);
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/{id}")
@Operation(

View File

@ -16,6 +16,7 @@ import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import org.openmetadata.schema.api.VoteRequest;
import org.openmetadata.schema.api.data.CreateStoredProcedure;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.DatabaseSchema;
@ -328,6 +329,27 @@ public class StoredProcedureResource extends EntityResource<StoredProcedure, Sto
.toResponse();
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/{id}")
@Operation(

View File

@ -47,6 +47,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.VoteRequest;
import org.openmetadata.schema.api.data.CreateTable;
import org.openmetadata.schema.api.data.CreateTableProfile;
import org.openmetadata.schema.api.data.RestoreEntity;
@ -856,6 +857,27 @@ public class TableResource extends EntityResource<Table, TableRepository> {
return addHref(uriInfo, table);
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/{id}/customMetric/{columnName}/{customMetricName}")
@Operation(

View File

@ -43,9 +43,11 @@ 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.VoteRequest;
import org.openmetadata.schema.api.data.CreateDashboardDataModel;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.DashboardDataModel;
import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
import org.openmetadata.service.Entity;
@ -353,6 +355,27 @@ public class DashboardDataModelResource extends EntityResource<DashboardDataMode
return repository.deleteFollower(securityContext.getUserPrincipal().getName(), id, userId).toResponse();
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/{id}")
@Operation(

View File

@ -45,9 +45,11 @@ 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.VoteRequest;
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.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
@ -301,6 +303,27 @@ public class GlossaryResource extends EntityResource<Glossary, GlossaryRepositor
return createOrUpdate(uriInfo, securityContext, glossary);
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/{id}")
@Operation(

View File

@ -44,10 +44,12 @@ 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.VoteRequest;
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.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.EntityReference;
import org.openmetadata.schema.type.Include;
@ -354,6 +356,27 @@ public class GlossaryTermResource extends EntityResource<GlossaryTerm, GlossaryT
return createOrUpdate(uriInfo, securityContext, term);
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/{id}")
@Operation(

View File

@ -41,7 +41,9 @@ 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.VoteRequest;
import org.openmetadata.schema.entity.data.Metrics;
import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
import org.openmetadata.service.jdbi3.CollectionDAO;
@ -159,6 +161,27 @@ public class MetricsResource extends EntityResource<Metrics, MetricsRepository>
return super.create(uriInfo, securityContext, metrics);
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@Override
@PUT
@Operation(

View File

@ -72,7 +72,7 @@ public class QueryResource extends EntityResource<Query, QueryRepository> {
@Override
protected List<MetadataOperation> getEntitySpecificOperations() {
addViewOperation("users,votes,queryUsedIn", MetadataOperation.VIEW_BASIC);
addViewOperation("users,queryUsedIn", MetadataOperation.VIEW_BASIC);
return null;
}
@ -321,9 +321,9 @@ public class QueryResource extends EntityResource<Query, QueryRepository> {
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVote",
summary = "Update Vote for a query",
description = "Update vote for a query",
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
@ -334,7 +334,7 @@ public class QueryResource extends EntityResource<Query, QueryRepository> {
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Query", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}

View File

@ -39,7 +39,9 @@ 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.VoteRequest;
import org.openmetadata.schema.entity.data.Report;
import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
import org.openmetadata.service.jdbi3.CollectionDAO;
@ -170,6 +172,27 @@ public class ReportResource extends EntityResource<Report, ReportRepository> {
return super.createOrUpdate(uriInfo, securityContext, report);
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
private void addToReport(SecurityContext securityContext, Report report) {
report
.withId(UUID.randomUUID())

View File

@ -46,6 +46,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.VoteRequest;
import org.openmetadata.schema.api.data.CreateSearchIndex;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.SearchIndex;
@ -407,6 +408,27 @@ public class SearchIndexResource extends EntityResource<SearchIndex, SearchIndex
.toResponse();
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/{id}")
@Operation(

View File

@ -31,6 +31,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.VoteRequest;
import org.openmetadata.schema.api.data.CreateContainer;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Container;
@ -379,6 +380,27 @@ public class ContainerResource extends EntityResource<Container, ContainerReposi
return delete(uriInfo, securityContext, id, false, hardDelete);
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/name/{fqn}")
@Operation(

View File

@ -46,6 +46,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.VoteRequest;
import org.openmetadata.schema.api.data.CreateTopic;
import org.openmetadata.schema.api.data.RestoreEntity;
import org.openmetadata.schema.entity.data.Topic;
@ -407,6 +408,27 @@ public class TopicResource extends EntityResource<Topic, TopicRepository> {
.toResponse();
}
@PUT
@Path("/{id}/vote")
@Operation(
operationId = "updateVoteForEntity",
summary = "Update Vote for a Entity",
description = "Update vote for a Entity",
responses = {
@ApiResponse(
responseCode = "200",
description = "OK",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ChangeEvent.class))),
@ApiResponse(responseCode = "404", description = "model for instance {id} is not found")
})
public Response updateVote(
@Context UriInfo uriInfo,
@Context SecurityContext securityContext,
@Parameter(description = "Id of the Entity", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid VoteRequest request) {
return repository.updateVote(securityContext.getUserPrincipal().getName(), id, request).toResponse();
}
@DELETE
@Path("/{id}")
@Operation(

View File

@ -39,6 +39,7 @@ import static org.openmetadata.service.Entity.FIELD_EXTENSION;
import static org.openmetadata.service.Entity.FIELD_FOLLOWERS;
import static org.openmetadata.service.Entity.FIELD_OWNER;
import static org.openmetadata.service.Entity.FIELD_TAGS;
import static org.openmetadata.service.Entity.FIELD_VOTES;
import static org.openmetadata.service.exception.CatalogExceptionMessage.ENTITY_ALREADY_EXISTS;
import static org.openmetadata.service.exception.CatalogExceptionMessage.entityIsNotEmpty;
import static org.openmetadata.service.exception.CatalogExceptionMessage.entityNotFound;
@ -224,6 +225,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
private final String allFields;
private final String systemEntityName; // System entity provided by the system that can't be deleted
protected final boolean supportsFollowers;
protected final boolean supportsVotes;
protected final boolean supportsOwner;
protected final boolean supportsTags;
protected boolean supportsPatch = true;
@ -393,6 +395,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
Set<String> allowedFields = Entity.getEntityFields(entityClass);
this.supportsEmptyDescription = !EntityUtil.isDescriptionRequired(entityClass);
this.supportsFollowers = allowedFields.contains(FIELD_FOLLOWERS);
this.supportsVotes = allowedFields.contains(FIELD_VOTES);
this.supportsOwner = allowedFields.contains(FIELD_OWNER);
this.supportsTags = allowedFields.contains(FIELD_TAGS);
this.supportsSoftDelete = allowedFields.contains(FIELD_DELETED);

View File

@ -160,6 +160,10 @@ public interface EntityInterface {
/* no-op implementation to be overridden */
}
default void setVotes(Votes vote) {
/* no-op implementation to be overridden */
}
<T extends EntityInterface> T withHref(URI href);
@JsonIgnore

View File

@ -147,6 +147,9 @@
"description": "List of data products this entity is part of.",
"$ref" : "../../type/entityReferenceList.json"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"

View File

@ -176,6 +176,9 @@
"description": "Domain the Container belongs to. When not set, the Container inherits the domain from the storage service it belongs to.",
"$ref": "../../type/entityReference.json"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"

View File

@ -135,6 +135,9 @@
"description": "List of data products this entity is part of.",
"$ref" : "../../type/entityReferenceList.json"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"

View File

@ -142,6 +142,9 @@
"description": "Domain the Dashboard Data Model belongs to. When not set, the Dashboard model inherits the domain from the dashboard service it belongs to.",
"$ref": "../../type/entityReference.json"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"

View File

@ -116,6 +116,9 @@
"description": "Domain the Database belongs to. When not set, the Database inherits the domain from the database service it belongs to.",
"$ref": "../../type/entityReference.json"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"

View File

@ -111,6 +111,9 @@
"description": "Domain the Database Schema belongs to. When not set, the Schema inherits the domain from the database it belongs to.",
"$ref": "../../type/entityReference.json"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"

View File

@ -95,6 +95,9 @@
"domain" : {
"description": "Domain the Glossary belongs to.",
"$ref": "../../type/entityReference.json"
},
"votes" : {
"$ref": "../../type/votes.json"
}
},
"required": ["id", "name", "description"],

View File

@ -143,6 +143,9 @@
"domain" : {
"description": "Domain the Glossary Term belongs to. When not set, the Glossary TErm inherits the domain from the Glossary it belongs to.",
"$ref": "../../type/entityReference.json"
},
"votes" : {
"$ref": "../../type/votes.json"
}
},
"required": ["id", "name", "description", "glossary"],

View File

@ -76,6 +76,9 @@
"domain" : {
"description": "Domain the Metrics belongs to.",
"$ref": "../../type/entityReference.json"
},
"votes" : {
"$ref": "../../type/votes.json"
}
},
"required": ["id", "name", "service"],

View File

@ -273,11 +273,13 @@
"description": "Domain the MLModel belongs to. When not set, the MLModel inherits the domain from the ML Model Service it belongs to.",
"$ref": "../../type/entityReference.json"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"
}
},
"required": ["id", "name", "algorithm", "service"],
"additionalProperties": false

View File

@ -259,6 +259,9 @@
"description": "Domain the Pipeline belongs to. When not set, the pipeline inherits the domain from the Pipeline service it belongs to.",
"$ref": "../../type/entityReference.json"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"

View File

@ -64,6 +64,9 @@
"description": "When `true` indicates the entity has been soft deleted.",
"type": "boolean",
"default": false
},
"votes" : {
"$ref": "../../type/votes.json"
}
},
"required": ["id", "name", "service"],

View File

@ -226,6 +226,9 @@
"dataProducts" : {
"description": "List of data products this entity is part of.",
"$ref" : "../../type/entityReferenceList.json"
},
"votes" : {
"$ref": "../../type/votes.json"
}
},
"required": ["id", "name", "service", "fields"],

View File

@ -1033,6 +1033,9 @@
"description": "File format in case of file/datalake tables.",
"$ref" : "#/definitions/fileFormat"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"

View File

@ -166,6 +166,9 @@
"description": "List of data products this entity is part of.",
"$ref" : "../../type/entityReferenceList.json"
},
"votes" : {
"$ref": "../../type/votes.json"
},
"lifeCycle": {
"description": "Life Cycle properties of the entity",
"$ref": "../../type/lifeCycle.json"