mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-28 17:23:28 +00:00
Add Chart and Dashboard Service entities
This commit is contained in:
parent
8f5b3c934d
commit
0e4a3b26f9
@ -78,8 +78,6 @@ public abstract class ChartRepository {
|
|||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
abstract TagRepository.TagDAO tagDAO();
|
abstract TagRepository.TagDAO tagDAO();
|
||||||
|
|
||||||
@CreateSqlObject
|
|
||||||
abstract UsageDAO usageDAO();
|
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
public List<Chart> listAfter(Fields fields, String serviceName, int limitParam, String after) throws IOException,
|
public List<Chart> listAfter(Fields fields, String serviceName, int limitParam, String after) throws IOException,
|
||||||
|
|||||||
@ -16,36 +16,59 @@
|
|||||||
|
|
||||||
package org.openmetadata.catalog.jdbi3;
|
package org.openmetadata.catalog.jdbi3;
|
||||||
|
|
||||||
|
import org.openmetadata.catalog.entity.data.Chart;
|
||||||
|
import org.openmetadata.catalog.entity.data.Database;
|
||||||
|
import org.openmetadata.catalog.entity.data.Table;
|
||||||
|
import org.openmetadata.catalog.exception.CatalogExceptionMessage;
|
||||||
|
import org.openmetadata.catalog.exception.EntityNotFoundException;
|
||||||
import org.openmetadata.catalog.jdbi3.TeamRepository.TeamDAO;
|
import org.openmetadata.catalog.jdbi3.TeamRepository.TeamDAO;
|
||||||
import org.openmetadata.catalog.jdbi3.UserRepository.UserDAO;
|
import org.openmetadata.catalog.jdbi3.UserRepository.UserDAO;
|
||||||
|
import org.openmetadata.catalog.resources.charts.ChartResource;
|
||||||
import org.openmetadata.catalog.resources.dashboards.DashboardResource;
|
import org.openmetadata.catalog.resources.dashboards.DashboardResource;
|
||||||
import org.openmetadata.catalog.Entity;
|
import org.openmetadata.catalog.Entity;
|
||||||
import org.openmetadata.catalog.entity.data.Dashboard;
|
import org.openmetadata.catalog.entity.data.Dashboard;
|
||||||
import org.openmetadata.catalog.jdbi3.UsageRepository.UsageDAO;
|
import org.openmetadata.catalog.jdbi3.UsageRepository.UsageDAO;
|
||||||
|
import org.openmetadata.catalog.jdbi3.ChartRepository.ChartDAO;
|
||||||
|
import org.openmetadata.catalog.jdbi3.DashboardServiceRepository.DashboardServiceDAO;
|
||||||
import org.openmetadata.catalog.type.EntityReference;
|
import org.openmetadata.catalog.type.EntityReference;
|
||||||
|
import org.openmetadata.catalog.type.TagLabel;
|
||||||
import org.openmetadata.catalog.util.EntityUtil;
|
import org.openmetadata.catalog.util.EntityUtil;
|
||||||
import org.openmetadata.catalog.util.EntityUtil.Fields;
|
import org.openmetadata.catalog.util.EntityUtil.Fields;
|
||||||
import org.openmetadata.catalog.util.JsonUtils;
|
import org.openmetadata.catalog.util.JsonUtils;
|
||||||
import org.openmetadata.catalog.util.RestUtil.PutResponse;
|
import org.openmetadata.catalog.util.RestUtil.PutResponse;
|
||||||
|
import org.openmetadata.common.utils.CipherText;
|
||||||
import org.skife.jdbi.v2.sqlobject.Bind;
|
import org.skife.jdbi.v2.sqlobject.Bind;
|
||||||
import org.skife.jdbi.v2.sqlobject.CreateSqlObject;
|
import org.skife.jdbi.v2.sqlobject.CreateSqlObject;
|
||||||
import org.skife.jdbi.v2.sqlobject.SqlQuery;
|
import org.skife.jdbi.v2.sqlobject.SqlQuery;
|
||||||
import org.skife.jdbi.v2.sqlobject.SqlUpdate;
|
import org.skife.jdbi.v2.sqlobject.SqlUpdate;
|
||||||
import org.skife.jdbi.v2.sqlobject.Transaction;
|
import org.skife.jdbi.v2.sqlobject.Transaction;
|
||||||
|
|
||||||
|
import javax.json.JsonPatch;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.openmetadata.catalog.exception.CatalogExceptionMessage.entityNotFound;
|
||||||
|
|
||||||
public abstract class DashboardRepository {
|
public abstract class DashboardRepository {
|
||||||
private static final Fields METRICS_UPDATE_FIELDS = new Fields(DashboardResource.FIELD_LIST,
|
private static final Fields DASHBOARD_UPDATE_FIELDS = new Fields(DashboardResource.FIELD_LIST,
|
||||||
"owner,service");
|
"owner,service,tags,charts");
|
||||||
|
private static final Fields DASHBOARD_PATCH_FIELDS = new Fields(DashboardResource.FIELD_LIST,
|
||||||
|
"owner,service,tags,charts");
|
||||||
|
|
||||||
|
|
||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
abstract DashboardDAO dashboardDAO();
|
abstract DashboardDAO dashboardDAO();
|
||||||
|
|
||||||
|
@CreateSqlObject
|
||||||
|
abstract ChartDAO chartDAO();
|
||||||
|
|
||||||
|
@CreateSqlObject
|
||||||
|
abstract DashboardServiceDAO dashboardServiceDAO();
|
||||||
|
|
||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
abstract EntityRelationshipDAO relationshipDAO();
|
abstract EntityRelationshipDAO relationshipDAO();
|
||||||
|
|
||||||
@ -58,6 +81,35 @@ public abstract class DashboardRepository {
|
|||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
abstract UsageDAO usageDAO();
|
abstract UsageDAO usageDAO();
|
||||||
|
|
||||||
|
@CreateSqlObject
|
||||||
|
abstract TagRepository.TagDAO tagDAO();
|
||||||
|
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public List<Dashboard> listAfter(Fields fields, String serviceName, int limitParam, String after) throws IOException,
|
||||||
|
GeneralSecurityException {
|
||||||
|
// forward scrolling, either because after != null or first page is being asked
|
||||||
|
List<String> jsons = dashboardDAO().listAfter(serviceName, limitParam, after == null ? "" :
|
||||||
|
CipherText.instance().decrypt(after));
|
||||||
|
|
||||||
|
List<Dashboard> dashboards = new ArrayList<>();
|
||||||
|
for (String json : jsons) {
|
||||||
|
dashboards.add(setFields(JsonUtils.readValue(json, Dashboard.class), fields));
|
||||||
|
}
|
||||||
|
return dashboards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public List<Dashboard> listBefore(Fields fields, String serviceName, int limitParam, String before)
|
||||||
|
throws IOException, GeneralSecurityException {
|
||||||
|
// Reverse scrolling
|
||||||
|
List<String> jsons = dashboardDAO().listBefore(serviceName, limitParam, CipherText.instance().decrypt(before));
|
||||||
|
List<Dashboard> dashboards = new ArrayList<>();
|
||||||
|
for (String json : jsons) {
|
||||||
|
dashboards.add(setFields(JsonUtils.readValue(json, Dashboard.class), fields));
|
||||||
|
}
|
||||||
|
return dashboards;
|
||||||
|
}
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
public Dashboard create(Dashboard dashboard, EntityReference service, EntityReference owner) throws IOException {
|
public Dashboard create(Dashboard dashboard, EntityReference service, EntityReference owner) throws IOException {
|
||||||
@ -81,8 +133,8 @@ public abstract class DashboardRepository {
|
|||||||
dashboardDAO().update(storedDashboard.getId().toString(), JsonUtils.pojoToJson(storedDashboard));
|
dashboardDAO().update(storedDashboard.getId().toString(), JsonUtils.pojoToJson(storedDashboard));
|
||||||
|
|
||||||
// Update owner relationship
|
// Update owner relationship
|
||||||
setFields(storedDashboard, METRICS_UPDATE_FIELDS); // First get the ownership information
|
setFields(storedDashboard, DASHBOARD_UPDATE_FIELDS); // First get the ownership information
|
||||||
updateOwner(storedDashboard, storedDashboard.getOwner(), newOwner);
|
updateRelationships(storedDashboard, updatedDashboard);
|
||||||
|
|
||||||
// Service can't be changed in update since service name is part of FQN and
|
// Service can't be changed in update since service name is part of FQN and
|
||||||
// change to a different service will result in a different FQN and creation of a new database under the new service
|
// change to a different service will result in a different FQN and creation of a new database under the new service
|
||||||
@ -91,27 +143,66 @@ public abstract class DashboardRepository {
|
|||||||
return new PutResponse<>(Response.Status.OK, storedDashboard);
|
return new PutResponse<>(Response.Status.OK, storedDashboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dashboard get(String id, Fields fields) throws IOException {
|
@Transaction
|
||||||
return setFields(EntityUtil.validate(id, dashboardDAO().findById(id), Dashboard.class), fields);
|
public Dashboard patch(String id, JsonPatch patch) throws IOException {
|
||||||
|
Dashboard original = setFields(validateDashboard(id), DASHBOARD_PATCH_FIELDS);
|
||||||
|
Dashboard updated = JsonUtils.applyPatch(original, patch, Dashboard.class);
|
||||||
|
patch(original, updated);
|
||||||
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Dashboard> list(Fields fields) throws IOException {
|
@Transaction
|
||||||
List<String> jsonList = dashboardDAO().list();
|
public Status addFollower(String dashboardId, String userId) throws IOException {
|
||||||
List<Dashboard> dashboardList = new ArrayList<>();
|
EntityUtil.validate(dashboardId, dashboardDAO().findById(dashboardId), Dashboard.class);
|
||||||
for (String json : jsonList) {
|
return EntityUtil.addFollower(relationshipDAO(), userDAO(), dashboardId, Entity.DASHBOARD, userId, Entity.USER) ?
|
||||||
dashboardList.add(setFields(JsonUtils.readValue(json, Dashboard.class), fields));
|
Status.CREATED : Status.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public void deleteFollower(String dashboardId, String userId) {
|
||||||
|
EntityUtil.validateUser(userDAO(), userId);
|
||||||
|
EntityUtil.removeFollower(relationshipDAO(), dashboardId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public void delete(String id) {
|
||||||
|
if (relationshipDAO().findToCount(id, Relationship.CONTAINS.ordinal(), Entity.DASHBOARD) > 0) {
|
||||||
|
throw new IllegalArgumentException("Dashboard is not empty");
|
||||||
}
|
}
|
||||||
return dashboardList;
|
if (dashboardDAO().delete(id) <= 0) {
|
||||||
|
throw EntityNotFoundException.byMessage(entityNotFound(Entity.DASHBOARD, id));
|
||||||
|
}
|
||||||
|
relationshipDAO().deleteAll(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<EntityReference> toEntityReference(List<Chart> charts) {
|
||||||
|
List<EntityReference> refList = new ArrayList<>();
|
||||||
|
for (Chart chart: charts) {
|
||||||
|
refList.add(EntityUtil.getEntityReference(chart));
|
||||||
|
}
|
||||||
|
return refList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dashboard get(String id, Fields fields) throws IOException {
|
||||||
|
return setFields(EntityUtil.validate(id, dashboardDAO().findById(id), Dashboard.class), fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dashboard setFields(Dashboard dashboard, Fields fields) throws IOException {
|
private Dashboard setFields(Dashboard dashboard, Fields fields) throws IOException {
|
||||||
dashboard.setOwner(fields.contains("owner") ? getOwner(dashboard) : null);
|
dashboard.setOwner(fields.contains("owner") ? getOwner(dashboard) : null);
|
||||||
dashboard.setService(fields.contains("service") ? getService(dashboard) : null);
|
dashboard.setService(fields.contains("service") ? getService(dashboard) : null);
|
||||||
|
dashboard.setFollowers(fields.contains("followers") ? getFollowers(dashboard) : null);
|
||||||
|
dashboard.setCharts(fields.contains("charts") ? toEntityReference(getCharts(dashboard)) : null);
|
||||||
|
dashboard.setTags(fields.contains("tags") ? getTags(dashboard.getFullyQualifiedName()) : null);
|
||||||
dashboard.setUsageSummary(fields.contains("usageSummary") ? EntityUtil.getLatestUsage(usageDAO(),
|
dashboard.setUsageSummary(fields.contains("usageSummary") ? EntityUtil.getLatestUsage(usageDAO(),
|
||||||
dashboard.getId()) : null);
|
dashboard.getId()) : null);
|
||||||
return dashboard;
|
return dashboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<TagLabel> getTags(String fqn) {
|
||||||
|
return tagDAO().getTags(fqn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private Dashboard createInternal(Dashboard dashboard, EntityReference service, EntityReference owner)
|
private Dashboard createInternal(Dashboard dashboard, EntityReference service, EntityReference owner)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String fqn = service.getName() + "." + dashboard.getName();
|
String fqn = service.getName() + "." + dashboard.getName();
|
||||||
@ -121,7 +212,7 @@ public abstract class DashboardRepository {
|
|||||||
|
|
||||||
dashboardDAO().insert(JsonUtils.pojoToJson(dashboard));
|
dashboardDAO().insert(JsonUtils.pojoToJson(dashboard));
|
||||||
setService(dashboard, service);
|
setService(dashboard, service);
|
||||||
setOwner(dashboard, owner);
|
addRelationships(dashboard);
|
||||||
return dashboard;
|
return dashboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +234,32 @@ public abstract class DashboardRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void patch(Dashboard original, Dashboard updated) throws IOException {
|
||||||
|
String dashboardId = original.getId().toString();
|
||||||
|
if (!original.getId().equals(updated.getId())) {
|
||||||
|
throw new IllegalArgumentException(CatalogExceptionMessage.readOnlyAttribute(Entity.DASHBOARD, "id"));
|
||||||
|
}
|
||||||
|
if (!original.getName().equals(updated.getName())) {
|
||||||
|
throw new IllegalArgumentException(CatalogExceptionMessage.readOnlyAttribute(Entity.DASHBOARD, "name"));
|
||||||
|
}
|
||||||
|
if (updated.getService() == null || !original.getService().getId().equals(updated.getService().getId())) {
|
||||||
|
throw new IllegalArgumentException(CatalogExceptionMessage.readOnlyAttribute(Entity.DASHBOARD,
|
||||||
|
"service"));
|
||||||
|
}
|
||||||
|
// Validate new owner
|
||||||
|
EntityReference newOwner = EntityUtil.populateOwner(userDAO(), teamDAO(), updated.getOwner());
|
||||||
|
|
||||||
|
EntityReference newService = updated.getService();
|
||||||
|
|
||||||
|
updated.setHref(null);
|
||||||
|
updated.setOwner(null);
|
||||||
|
updated.setService(null);
|
||||||
|
dashboardDAO().update(dashboardId, JsonUtils.pojoToJson(updated));
|
||||||
|
updateOwner(updated, original.getOwner(), newOwner);
|
||||||
|
updated.setService(newService);
|
||||||
|
applyTags(updated);
|
||||||
|
}
|
||||||
|
|
||||||
private EntityReference getOwner(Dashboard dashboard) throws IOException {
|
private EntityReference getOwner(Dashboard dashboard) throws IOException {
|
||||||
return dashboard == null ? null : EntityUtil.populateOwner(dashboard.getId(), relationshipDAO(),
|
return dashboard == null ? null : EntityUtil.populateOwner(dashboard.getId(), relationshipDAO(),
|
||||||
userDAO(), teamDAO());
|
userDAO(), teamDAO());
|
||||||
@ -158,6 +275,57 @@ public abstract class DashboardRepository {
|
|||||||
dashboard.setOwner(newOwner);
|
dashboard.setOwner(newOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyTags(Dashboard dashboard) throws IOException {
|
||||||
|
// Add dashboard level tags by adding tag to dashboard relationship
|
||||||
|
EntityUtil.applyTags(tagDAO(), dashboard.getTags(), dashboard.getFullyQualifiedName());
|
||||||
|
dashboard.setTags(getTags(dashboard.getFullyQualifiedName())); // Update tag to handle additional derived tags
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<EntityReference> getFollowers(Dashboard dashboard) throws IOException {
|
||||||
|
return dashboard == null ? null : EntityUtil.getFollowers(dashboard.getId(), relationshipDAO(), userDAO());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Chart> getCharts(Dashboard dashboard) throws IOException {
|
||||||
|
if (dashboard == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String dashboardId = dashboard.getId().toString();
|
||||||
|
List<String> chartIds = relationshipDAO().findTo(dashboardId, Relationship.CONTAINS.ordinal(), Entity.CHART);
|
||||||
|
List<Chart> charts = new ArrayList<>();
|
||||||
|
for (String chartId : chartIds) {
|
||||||
|
String json = chartDAO().findById(chartId);
|
||||||
|
Chart chart = JsonUtils.readValue(json, Chart.class);
|
||||||
|
charts.add(chart);
|
||||||
|
}
|
||||||
|
return charts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRelationships(Dashboard dashboard) throws IOException {
|
||||||
|
// Add relationship from dashboard to chart
|
||||||
|
String dashboardId = dashboard.getId().toString();
|
||||||
|
for (EntityReference chart: dashboard.getCharts()) {
|
||||||
|
relationshipDAO().insert(dashboardId, chart.getId().toString(), Entity.DASHBOARD, Entity.CHART,
|
||||||
|
Relationship.CONTAINS.ordinal());
|
||||||
|
}
|
||||||
|
// Add owner relationship
|
||||||
|
EntityUtil.setOwner(relationshipDAO(), dashboard.getId(), Entity.DASHBOARD, dashboard.getOwner());
|
||||||
|
|
||||||
|
// Add tag to dashboard relationship
|
||||||
|
applyTags(dashboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRelationships(Dashboard origDashboard, Dashboard updatedDashboard) throws IOException {
|
||||||
|
// Add owner relationship
|
||||||
|
origDashboard.setOwner(getOwner(origDashboard));
|
||||||
|
EntityUtil.updateOwner(relationshipDAO(), origDashboard.getOwner(), updatedDashboard.getOwner(),
|
||||||
|
origDashboard.getId(), Entity.TABLE);
|
||||||
|
applyTags(updatedDashboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dashboard validateDashboard(String id) throws IOException {
|
||||||
|
return EntityUtil.validate(id, dashboardDAO().findById(id), Dashboard.class);
|
||||||
|
}
|
||||||
|
|
||||||
public interface DashboardDAO {
|
public interface DashboardDAO {
|
||||||
@SqlUpdate("INSERT INTO dashboard_entity(json) VALUES (:json)")
|
@SqlUpdate("INSERT INTO dashboard_entity(json) VALUES (:json)")
|
||||||
void insert(@Bind("json") String json);
|
void insert(@Bind("json") String json);
|
||||||
@ -171,7 +339,28 @@ public abstract class DashboardRepository {
|
|||||||
@SqlQuery("SELECT json FROM dashboard_entity WHERE fullyQualifiedName = :name")
|
@SqlQuery("SELECT json FROM dashboard_entity WHERE fullyQualifiedName = :name")
|
||||||
String findByFQN(@Bind("name") String name);
|
String findByFQN(@Bind("name") String name);
|
||||||
|
|
||||||
@SqlQuery("SELECT json FROM dashboard_entity")
|
@SqlQuery(
|
||||||
List<String> list();
|
"SELECT json FROM (" +
|
||||||
|
"SELECT fullyQualifiedName, json FROM dashboard_entity WHERE " +
|
||||||
|
"(fullyQualifiedName LIKE CONCAT(:fqnPrefix, '.%') OR :fqnPrefix IS NULL) AND " +// Filter by
|
||||||
|
// service name
|
||||||
|
"fullyQualifiedName < :before " + // Pagination by dashboard fullyQualifiedName
|
||||||
|
"ORDER BY fullyQualifiedName DESC " + // Pagination ordering by chart fullyQualifiedName
|
||||||
|
"LIMIT :limit" +
|
||||||
|
") last_rows_subquery ORDER BY fullyQualifiedName")
|
||||||
|
List<String> listBefore(@Bind("fqnPrefix") String fqnPrefix, @Bind("limit") int limit,
|
||||||
|
@Bind("before") String before);
|
||||||
|
|
||||||
|
@SqlQuery("SELECT json FROM chart_entity WHERE " +
|
||||||
|
"(fullyQualifiedName LIKE CONCAT(:fqnPrefix, '.%') OR :fqnPrefix IS NULL) AND " +
|
||||||
|
"fullyQualifiedName > :after " +
|
||||||
|
"ORDER BY fullyQualifiedName " +
|
||||||
|
"LIMIT :limit")
|
||||||
|
List<String> listAfter(@Bind("fqnPrefix") String fqnPrefix, @Bind("limit") int limit,
|
||||||
|
@Bind("after") String after);
|
||||||
|
|
||||||
|
|
||||||
|
@SqlUpdate("DELETE FROM dashboard_entity WHERE id = :id")
|
||||||
|
int delete(@Bind("id") String id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,7 +80,7 @@ public abstract class TableRepository {
|
|||||||
"owner,columns,database,tags,tableConstraints");
|
"owner,columns,database,tags,tableConstraints");
|
||||||
// Table fields that can be updated in a PUT request
|
// Table fields that can be updated in a PUT request
|
||||||
private static final Fields TABLE_UPDATE_FIELDS = new Fields(TableResource.FIELD_LIST,
|
private static final Fields TABLE_UPDATE_FIELDS = new Fields(TableResource.FIELD_LIST,
|
||||||
"owner,columns,database,tags, tableConstraints");
|
"owner,columns,database,tags,tableConstraints");
|
||||||
|
|
||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
abstract DatabaseDAO databaseDAO();
|
abstract DatabaseDAO databaseDAO();
|
||||||
|
|||||||
@ -27,12 +27,9 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import org.openmetadata.catalog.api.data.CreateChart;
|
import org.openmetadata.catalog.api.data.CreateChart;
|
||||||
import org.openmetadata.catalog.api.data.CreateTopic;
|
|
||||||
import org.openmetadata.catalog.entity.data.Chart;
|
import org.openmetadata.catalog.entity.data.Chart;
|
||||||
import org.openmetadata.catalog.entity.data.Dashboard;
|
import org.openmetadata.catalog.entity.data.Dashboard;
|
||||||
import org.openmetadata.catalog.entity.data.Topic;
|
|
||||||
import org.openmetadata.catalog.jdbi3.ChartRepository;
|
import org.openmetadata.catalog.jdbi3.ChartRepository;
|
||||||
import org.openmetadata.catalog.jdbi3.TopicRepository;
|
|
||||||
import org.openmetadata.catalog.resources.Collection;
|
import org.openmetadata.catalog.resources.Collection;
|
||||||
import org.openmetadata.catalog.security.CatalogAuthorizer;
|
import org.openmetadata.catalog.security.CatalogAuthorizer;
|
||||||
import org.openmetadata.catalog.security.SecurityUtil;
|
import org.openmetadata.catalog.security.SecurityUtil;
|
||||||
@ -80,7 +77,7 @@ import java.util.UUID;
|
|||||||
@Api(value = "Chart data asset collection", tags = "Chart data asset collection")
|
@Api(value = "Chart data asset collection", tags = "Chart data asset collection")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@Collection(name = "topics", repositoryClass = "org.openmetadata.catalog.jdbi3.ChartRepository")
|
@Collection(name = "charts", repositoryClass = "org.openmetadata.catalog.jdbi3.ChartRepository")
|
||||||
public class ChartResource {
|
public class ChartResource {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ChartResource.class);
|
private static final Logger LOG = LoggerFactory.getLogger(ChartResource.class);
|
||||||
private static final String CHART_COLLECTION_PATH = "v1/charts/";
|
private static final String CHART_COLLECTION_PATH = "v1/charts/";
|
||||||
@ -146,15 +143,15 @@ public class ChartResource {
|
|||||||
@Parameter(description = "Filter charts by service name",
|
@Parameter(description = "Filter charts by service name",
|
||||||
schema = @Schema(type = "string", example = "superset"))
|
schema = @Schema(type = "string", example = "superset"))
|
||||||
@QueryParam("service") String serviceParam,
|
@QueryParam("service") String serviceParam,
|
||||||
@Parameter(description = "Limit the number topics returned. (1 to 1000000, default = 10)")
|
@Parameter(description = "Limit the number charts returned. (1 to 1000000, default = 10)")
|
||||||
@DefaultValue("10")
|
@DefaultValue("10")
|
||||||
@Min(1)
|
@Min(1)
|
||||||
@Max(1000000)
|
@Max(1000000)
|
||||||
@QueryParam("limit") int limitParam,
|
@QueryParam("limit") int limitParam,
|
||||||
@Parameter(description = "Returns list of topics before this cursor",
|
@Parameter(description = "Returns list of charts before this cursor",
|
||||||
schema = @Schema(type = "string"))
|
schema = @Schema(type = "string"))
|
||||||
@QueryParam("before") String before,
|
@QueryParam("before") String before,
|
||||||
@Parameter(description = "Returns list of topics after this cursor",
|
@Parameter(description = "Returns list of charts after this cursor",
|
||||||
schema = @Schema(type = "string"))
|
schema = @Schema(type = "string"))
|
||||||
@QueryParam("after") String after
|
@QueryParam("after") String after
|
||||||
) throws IOException, GeneralSecurityException {
|
) throws IOException, GeneralSecurityException {
|
||||||
@ -191,10 +188,10 @@ public class ChartResource {
|
|||||||
@Operation(summary = "Get a Chart", tags = "charts",
|
@Operation(summary = "Get a Chart", tags = "charts",
|
||||||
description = "Get a chart by `id`.",
|
description = "Get a chart by `id`.",
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(responseCode = "200", description = "The topic",
|
@ApiResponse(responseCode = "200", description = "The chart",
|
||||||
content = @Content(mediaType = "application/json",
|
content = @Content(mediaType = "application/json",
|
||||||
schema = @Schema(implementation = Dashboard.class))),
|
schema = @Schema(implementation = Dashboard.class))),
|
||||||
@ApiResponse(responseCode = "404", description = "Topic for instance {id} is not found")
|
@ApiResponse(responseCode = "404", description = "Chart for instance {id} is not found")
|
||||||
})
|
})
|
||||||
public Chart get(@Context UriInfo uriInfo, @PathParam("id") String id,
|
public Chart get(@Context UriInfo uriInfo, @PathParam("id") String id,
|
||||||
@Context SecurityContext securityContext,
|
@Context SecurityContext securityContext,
|
||||||
@ -213,7 +210,7 @@ public class ChartResource {
|
|||||||
@ApiResponse(responseCode = "200", description = "The chart",
|
@ApiResponse(responseCode = "200", description = "The chart",
|
||||||
content = @Content(mediaType = "application/json",
|
content = @Content(mediaType = "application/json",
|
||||||
schema = @Schema(implementation = Chart.class))),
|
schema = @Schema(implementation = Chart.class))),
|
||||||
@ApiResponse(responseCode = "404", description = "Topic for instance {id} is not found")
|
@ApiResponse(responseCode = "404", description = "Chart for instance {id} is not found")
|
||||||
})
|
})
|
||||||
public Response getByName(@Context UriInfo uriInfo, @PathParam("fqn") String fqn,
|
public Response getByName(@Context UriInfo uriInfo, @PathParam("fqn") String fqn,
|
||||||
@Context SecurityContext securityContext,
|
@Context SecurityContext securityContext,
|
||||||
@ -230,7 +227,7 @@ public class ChartResource {
|
|||||||
@Operation(summary = "Create a chart", tags = "charts",
|
@Operation(summary = "Create a chart", tags = "charts",
|
||||||
description = "Create a chart under an existing `service`.",
|
description = "Create a chart under an existing `service`.",
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(responseCode = "200", description = "The topic",
|
@ApiResponse(responseCode = "200", description = "The chart",
|
||||||
content = @Content(mediaType = "application/json",
|
content = @Content(mediaType = "application/json",
|
||||||
schema = @Schema(implementation = Chart.class))),
|
schema = @Schema(implementation = Chart.class))),
|
||||||
@ApiResponse(responseCode = "400", description = "Bad request")
|
@ApiResponse(responseCode = "400", description = "Bad request")
|
||||||
@ -302,7 +299,7 @@ public class ChartResource {
|
|||||||
description = "Add a user identified by `userId` as followed of this chart",
|
description = "Add a user identified by `userId` as followed of this chart",
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(responseCode = "200", description = "OK"),
|
@ApiResponse(responseCode = "200", description = "OK"),
|
||||||
@ApiResponse(responseCode = "404", description = "Topic for instance {id} is not found")
|
@ApiResponse(responseCode = "404", description = "Chart for instance {id} is not found")
|
||||||
})
|
})
|
||||||
public Response addFollower(@Context UriInfo uriInfo,
|
public Response addFollower(@Context UriInfo uriInfo,
|
||||||
@Context SecurityContext securityContext,
|
@Context SecurityContext securityContext,
|
||||||
@ -320,7 +317,7 @@ public class ChartResource {
|
|||||||
@DELETE
|
@DELETE
|
||||||
@Path("/{id}/followers/{userId}")
|
@Path("/{id}/followers/{userId}")
|
||||||
@Operation(summary = "Remove a follower", tags = "charts",
|
@Operation(summary = "Remove a follower", tags = "charts",
|
||||||
description = "Remove the user identified `userId` as a follower of the topic.")
|
description = "Remove the user identified `userId` as a follower of the chart.")
|
||||||
public Chart deleteFollower(@Context UriInfo uriInfo,
|
public Chart deleteFollower(@Context UriInfo uriInfo,
|
||||||
@Context SecurityContext securityContext,
|
@Context SecurityContext securityContext,
|
||||||
@Parameter(description = "Id of the chart",
|
@Parameter(description = "Id of the chart",
|
||||||
|
|||||||
@ -17,10 +17,16 @@
|
|||||||
package org.openmetadata.catalog.resources.dashboards;
|
package org.openmetadata.catalog.resources.dashboards;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import io.swagger.v3.oas.annotations.ExternalDocumentation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||||
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
|
import org.openmetadata.catalog.api.data.CreateDashboard;
|
||||||
|
import org.openmetadata.catalog.entity.data.Chart;
|
||||||
import org.openmetadata.catalog.entity.data.Dashboard;
|
import org.openmetadata.catalog.entity.data.Dashboard;
|
||||||
import org.openmetadata.catalog.jdbi3.DashboardRepository;
|
import org.openmetadata.catalog.jdbi3.DashboardRepository;
|
||||||
import org.openmetadata.catalog.resources.Collection;
|
import org.openmetadata.catalog.resources.Collection;
|
||||||
import org.openmetadata.catalog.security.SecurityUtil;
|
import org.openmetadata.catalog.security.SecurityUtil;
|
||||||
|
import org.openmetadata.catalog.util.EntityUtil;
|
||||||
import org.openmetadata.catalog.util.EntityUtil.Fields;
|
import org.openmetadata.catalog.util.EntityUtil.Fields;
|
||||||
import org.openmetadata.catalog.util.RestUtil;
|
import org.openmetadata.catalog.util.RestUtil;
|
||||||
import org.openmetadata.catalog.util.RestUtil.PutResponse;
|
import org.openmetadata.catalog.util.RestUtil.PutResponse;
|
||||||
@ -33,9 +39,15 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import org.openmetadata.catalog.security.CatalogAuthorizer;
|
import org.openmetadata.catalog.security.CatalogAuthorizer;
|
||||||
|
|
||||||
|
import javax.json.JsonPatch;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.Max;
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.DefaultValue;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.PATCH;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.PUT;
|
import javax.ws.rs.PUT;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
@ -49,6 +61,9 @@ import javax.ws.rs.core.SecurityContext;
|
|||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.text.ParseException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -87,29 +102,78 @@ public class DashboardResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class DashboardList extends ResultList<Dashboard> {
|
static class DashboardList extends ResultList<Dashboard> {
|
||||||
DashboardList(List<Dashboard> data) {
|
@SuppressWarnings("unused")
|
||||||
super(data);
|
DashboardList() {
|
||||||
|
// Empty constructor needed for deserialization
|
||||||
|
}
|
||||||
|
|
||||||
|
DashboardList(List<Dashboard> data, int limitParam, String beforeCursor,
|
||||||
|
String afterCursor) throws GeneralSecurityException, UnsupportedEncodingException {
|
||||||
|
super(data, limitParam, beforeCursor, afterCursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final String FIELDS ="owner,service,usageSummary";
|
static final String FIELDS = "owner,service,followers,tags,usageSummary";
|
||||||
public static final List<String> FIELD_LIST = Arrays.asList(FIELDS.replaceAll(" ", "")
|
public static final List<String> FIELD_LIST = Arrays.asList(FIELDS.replaceAll(" ", "")
|
||||||
.split(","));
|
.split(","));
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Operation(summary = "List dashboards", tags = "dashboards",
|
@Valid
|
||||||
description = "Get a list of dashboards. Use `fields` parameter to get only necessary fields.",
|
@Operation(summary = "List Dashboards", tags = "dashboards",
|
||||||
|
description = "Get a list of dashboards, optionally filtered by `service` it belongs to. Use `fields` " +
|
||||||
|
"parameter to get only necessary fields. Use cursor-based pagination to limit the number " +
|
||||||
|
"entries in the list using `limit` and `before` or `after` query params.",
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(responseCode = "200", description = "List of dashboards",
|
@ApiResponse(responseCode = "200", description = "List of dashboardss",
|
||||||
content = @Content(mediaType = "application/json",
|
content = @Content(mediaType = "application/json",
|
||||||
schema = @Schema(implementation = DashboardList.class)))
|
schema = @Schema(implementation = DashboardList.class)))
|
||||||
})
|
})
|
||||||
public DashboardList list(@Context UriInfo uriInfo,
|
public DashboardList list(@Context UriInfo uriInfo,
|
||||||
@Context SecurityContext securityContext,
|
@Context SecurityContext securityContext,
|
||||||
@Parameter(description = "Fields requested in the returned resource",
|
@Parameter(description = "Fields requested in the returned resource",
|
||||||
schema = @Schema(type = "string", example = FIELDS))
|
schema = @Schema(type = "string", example = FIELDS))
|
||||||
@QueryParam("fields") String fieldsParam) throws IOException {
|
@QueryParam("fields") String fieldsParam,
|
||||||
|
@Parameter(description = "Filter dashboards by service name",
|
||||||
|
schema = @Schema(type = "string", example = "superset"))
|
||||||
|
@QueryParam("service") String serviceParam,
|
||||||
|
@Parameter(description = "Limit the number dashboards returned. (1 to 1000000, default = 10)")
|
||||||
|
@DefaultValue("10")
|
||||||
|
@Min(1)
|
||||||
|
@Max(1000000)
|
||||||
|
@QueryParam("limit") int limitParam,
|
||||||
|
@Parameter(description = "Returns list of dashboards before this cursor",
|
||||||
|
schema = @Schema(type = "string"))
|
||||||
|
@QueryParam("before") String before,
|
||||||
|
@Parameter(description = "Returns list of dashboards after this cursor",
|
||||||
|
schema = @Schema(type = "string"))
|
||||||
|
@QueryParam("after") String after
|
||||||
|
) throws IOException, GeneralSecurityException {
|
||||||
|
RestUtil.validateCursors(before, after);
|
||||||
Fields fields = new Fields(FIELD_LIST, fieldsParam);
|
Fields fields = new Fields(FIELD_LIST, fieldsParam);
|
||||||
return new DashboardList(addHref(uriInfo, dao.list(fields)));
|
|
||||||
|
List<Dashboard> dashboards;
|
||||||
|
String beforeCursor = null, afterCursor = null;
|
||||||
|
|
||||||
|
// For calculating cursors, ask for one extra entry beyond limit. If the extra entry exists, then in forward
|
||||||
|
// scrolling afterCursor is not null. Similarly, if the extra entry exists, then in reverse scrolling,
|
||||||
|
// beforeCursor is not null. Remove the extra entry before returning results.
|
||||||
|
if (before != null) { // Reverse paging
|
||||||
|
dashboards = dao.listBefore(fields, serviceParam, limitParam + 1, before); // Ask for one extra entry
|
||||||
|
if (dashboards.size() > limitParam) {
|
||||||
|
dashboards.remove(0);
|
||||||
|
beforeCursor = dashboards.get(0).getFullyQualifiedName();
|
||||||
|
}
|
||||||
|
afterCursor = dashboards.get(dashboards.size() - 1).getFullyQualifiedName();
|
||||||
|
} else { // Forward paging or first page
|
||||||
|
dashboards = dao.listAfter(fields, serviceParam, limitParam + 1, after);
|
||||||
|
beforeCursor = after == null ? null : dashboards.get(0).getFullyQualifiedName();
|
||||||
|
if (dashboards.size() > limitParam) {
|
||||||
|
dashboards.remove(limitParam);
|
||||||
|
afterCursor = dashboards.get(limitParam - 1).getFullyQualifiedName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addHref(uriInfo, dashboards);
|
||||||
|
return new DashboardList(dashboards, limitParam, beforeCursor, afterCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@ -142,13 +206,40 @@ public class DashboardResource {
|
|||||||
@ApiResponse(responseCode = "400", description = "Bad request")
|
@ApiResponse(responseCode = "400", description = "Bad request")
|
||||||
})
|
})
|
||||||
public Response create(@Context UriInfo uriInfo, @Context SecurityContext securityContext,
|
public Response create(@Context UriInfo uriInfo, @Context SecurityContext securityContext,
|
||||||
@Valid Dashboard dashboard) throws IOException {
|
@Valid CreateDashboard create) throws IOException {
|
||||||
SecurityUtil.checkAdminOrBotRole(authorizer, securityContext);
|
SecurityUtil.checkAdminOrBotRole(authorizer, securityContext);
|
||||||
dashboard.setId(UUID.randomUUID());
|
Dashboard dashboard = new Dashboard().withId(UUID.randomUUID()).withName(create.getName())
|
||||||
|
.withService(create.getService()).withCharts(create.getCharts())
|
||||||
|
.withDashboardUrl(create.getDashboardUrl()).withTags(create.getTags());
|
||||||
addHref(uriInfo, dao.create(dashboard, dashboard.getService(), dashboard.getOwner()));
|
addHref(uriInfo, dao.create(dashboard, dashboard.getService(), dashboard.getOwner()));
|
||||||
return Response.created(dashboard.getHref()).entity(dashboard).build();
|
return Response.created(dashboard.getHref()).entity(dashboard).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PATCH
|
||||||
|
@Path("/{id}")
|
||||||
|
@Operation(summary = "Update a Dashboard", tags = "dashboards",
|
||||||
|
description = "Update an existing dashboard using JsonPatch.",
|
||||||
|
externalDocs = @ExternalDocumentation(description = "JsonPatch RFC",
|
||||||
|
url = "https://tools.ietf.org/html/rfc6902"))
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON_PATCH_JSON)
|
||||||
|
public Dashboard updateDescription(@Context UriInfo uriInfo,
|
||||||
|
@Context SecurityContext securityContext,
|
||||||
|
@PathParam("id") String id,
|
||||||
|
@RequestBody(description = "JsonPatch with array of operations",
|
||||||
|
content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON,
|
||||||
|
examples = {@ExampleObject("[" +
|
||||||
|
"{op:remove, path:/a}," +
|
||||||
|
"{op:add, path: /b, value: val}" +
|
||||||
|
"]")}))
|
||||||
|
JsonPatch patch) throws IOException {
|
||||||
|
Fields fields = new Fields(FIELD_LIST, FIELDS);
|
||||||
|
Dashboard dashboard = dao.get(id, fields);
|
||||||
|
SecurityUtil.checkAdminRoleOrPermissions(authorizer, securityContext,
|
||||||
|
EntityUtil.getEntityReference(dashboard));
|
||||||
|
dashboard = dao.patch(id, patch);
|
||||||
|
return addHref(uriInfo, dashboard);
|
||||||
|
}
|
||||||
|
|
||||||
@PUT
|
@PUT
|
||||||
@Operation(summary = "Create or update a dashboard", tags = "dashboards",
|
@Operation(summary = "Create or update a dashboard", tags = "dashboards",
|
||||||
description = "Create a new dashboard, if it does not exist or update an existing dashboard.",
|
description = "Create a new dashboard, if it does not exist or update an existing dashboard.",
|
||||||
@ -159,10 +250,65 @@ public class DashboardResource {
|
|||||||
@ApiResponse(responseCode = "400", description = "Bad request")
|
@ApiResponse(responseCode = "400", description = "Bad request")
|
||||||
})
|
})
|
||||||
public Response createOrUpdate(@Context UriInfo uriInfo, @Context SecurityContext securityContext,
|
public Response createOrUpdate(@Context UriInfo uriInfo, @Context SecurityContext securityContext,
|
||||||
@Valid Dashboard dashboard) throws IOException {
|
@Valid Dashboard create) throws IOException {
|
||||||
dashboard.setId(UUID.randomUUID());
|
Dashboard dashboard = new Dashboard().withId(UUID.randomUUID()).withName(create.getName())
|
||||||
|
.withService(create.getService()).withCharts(create.getCharts())
|
||||||
|
.withDashboardUrl(create.getDashboardUrl()).withTags(create.getTags());
|
||||||
|
addHref(uriInfo, dao.create(dashboard, dashboard.getService(), dashboard.getOwner()));
|
||||||
PutResponse<Dashboard> response = dao.createOrUpdate(dashboard, dashboard.getService(), dashboard.getOwner());
|
PutResponse<Dashboard> response = dao.createOrUpdate(dashboard, dashboard.getService(), dashboard.getOwner());
|
||||||
addHref(uriInfo, response.getEntity());
|
addHref(uriInfo, response.getEntity());
|
||||||
return Response.status(response.getStatus()).entity(response.getEntity()).build();
|
return Response.status(response.getStatus()).entity(response.getEntity()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/{id}/followers")
|
||||||
|
@Operation(summary = "Add a follower", tags = "dashboards",
|
||||||
|
description = "Add a user identified by `userId` as follower of this dashboard",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK"),
|
||||||
|
@ApiResponse(responseCode = "404", description = "Dashboard for instance {id} is not found")
|
||||||
|
})
|
||||||
|
public Response addFollower(@Context UriInfo uriInfo,
|
||||||
|
@Context SecurityContext securityContext,
|
||||||
|
@Parameter(description = "Id of the dashboard", schema = @Schema(type = "string"))
|
||||||
|
@PathParam("id") String id,
|
||||||
|
@Parameter(description = "Id of the user to be added as follower",
|
||||||
|
schema = @Schema(type = "string"))
|
||||||
|
String userId) throws IOException, ParseException {
|
||||||
|
Fields fields = new Fields(FIELD_LIST, "followers");
|
||||||
|
Response.Status status = dao.addFollower(id, userId);
|
||||||
|
Dashboard dashboard = dao.get(id, fields);
|
||||||
|
return Response.status(status).entity(dashboard).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/{id}/followers/{userId}")
|
||||||
|
@Operation(summary = "Remove a follower", tags = "dashboards",
|
||||||
|
description = "Remove the user identified `userId` as a follower of the dashboard.")
|
||||||
|
public Dashboard deleteFollower(@Context UriInfo uriInfo,
|
||||||
|
@Context SecurityContext securityContext,
|
||||||
|
@Parameter(description = "Id of the dashboard",
|
||||||
|
schema = @Schema(type = "string"))
|
||||||
|
@PathParam("id") String id,
|
||||||
|
@Parameter(description = "Id of the user being removed as follower",
|
||||||
|
schema = @Schema(type = "string"))
|
||||||
|
@PathParam("userId") String userId) throws IOException, ParseException {
|
||||||
|
Fields fields = new Fields(FIELD_LIST, "followers");
|
||||||
|
dao.deleteFollower(id, userId);
|
||||||
|
Dashboard dashboard = dao.get(id, fields);
|
||||||
|
return addHref(uriInfo, dashboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/{id}")
|
||||||
|
@Operation(summary = "Delete a Dashboard", tags = "dashboards",
|
||||||
|
description = "Delete a dashboard by `id`.",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK"),
|
||||||
|
@ApiResponse(responseCode = "404", description = "Dashboard for instance {id} is not found")
|
||||||
|
})
|
||||||
|
public Response delete(@Context UriInfo uriInfo, @PathParam("id") String id) {
|
||||||
|
dao.delete(id);
|
||||||
|
return Response.ok().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,14 @@
|
|||||||
},
|
},
|
||||||
"default": null
|
"default": null
|
||||||
},
|
},
|
||||||
|
"tags": {
|
||||||
|
"description": "Tags for this chart",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "../../type/tagLabel.json"
|
||||||
|
},
|
||||||
|
"default": null
|
||||||
|
},
|
||||||
"owner": {
|
"owner": {
|
||||||
"description": "Owner of this database",
|
"description": "Owner of this database",
|
||||||
"$ref": "../../type/entityReference.json"
|
"$ref": "../../type/entityReference.json"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user