Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RHCLOUD-36297 | refactor: handlers' versioning #3128

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.redhat.cloud.notifications.routers;
package com.redhat.cloud.notifications.routers.handlers.drawer;

import com.redhat.cloud.notifications.db.Query;
import com.redhat.cloud.notifications.db.repositories.DrawerNotificationRepository;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.redhat.cloud.notifications.routers;
package com.redhat.cloud.notifications.routers.handlers.endpoint;

import com.redhat.cloud.notifications.Constants;
import com.redhat.cloud.notifications.auth.ConsoleIdentityProvider;
Expand Down Expand Up @@ -27,7 +27,6 @@
import com.redhat.cloud.notifications.models.EndpointStatus;
import com.redhat.cloud.notifications.models.EndpointType;
import com.redhat.cloud.notifications.models.EventType;
import com.redhat.cloud.notifications.models.NotificationHistory;
import com.redhat.cloud.notifications.models.SourcesSecretable;
import com.redhat.cloud.notifications.models.SystemSubscriptionProperties;
import com.redhat.cloud.notifications.models.dto.v1.ApplicationDTO;
Expand All @@ -42,8 +41,6 @@
import com.redhat.cloud.notifications.routers.engine.EndpointTestService;
import com.redhat.cloud.notifications.routers.models.EndpointPage;
import com.redhat.cloud.notifications.routers.models.Meta;
import com.redhat.cloud.notifications.routers.models.Page;
import com.redhat.cloud.notifications.routers.models.PageLinksBuilder;
import com.redhat.cloud.notifications.routers.models.RequestSystemSubscriptionProperties;
import com.redhat.cloud.notifications.routers.sources.SecretUtils;
import io.quarkus.logging.Log;
Expand All @@ -69,7 +66,6 @@
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.UriInfo;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
Expand Down Expand Up @@ -214,124 +210,6 @@ protected List<NotificationHistoryDTO> internalGetEndpointHistory(final Security
}
}

@Path(Constants.API_INTEGRATIONS_V_2_0 + "/endpoints")
static class V2 extends EndpointResource {

@GET
@Path("/{id}/history")
@Produces(APPLICATION_JSON)
@Parameters({
@Parameter(
name = "limit",
in = ParameterIn.QUERY,
description = "Number of items per page, if not specified or 0 is used, returns a maximum of " + MAX_NOTIFICATION_HISTORY_RESULTS + " elements.",
schema = @Schema(type = SchemaType.INTEGER)
),
@Parameter(
name = "pageNumber",
in = ParameterIn.QUERY,
description = "Page number. Starts at first page (0), if not specified starts at first page.",
schema = @Schema(type = SchemaType.INTEGER)
),
@Parameter(
name = "includeDetail",
description = "Include the detail in the reply",
schema = @Schema(type = SchemaType.BOOLEAN)
)
})
public Page<NotificationHistoryDTO> getEndpointHistory(
@Context SecurityContext sec,
@Context UriInfo uriInfo,
@PathParam("id") UUID id,
@QueryParam("includeDetail") Boolean includeDetail,
@BeanParam Query query
) {
if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) {
this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW_HISTORY, id);

return this.internalGetEndpointHistory(sec, uriInfo, id, includeDetail, query);
} else {
return this.legacyRBACGetEndpointHistory(sec, uriInfo, id, includeDetail, query);
}
}

@RolesAllowed(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS)
protected Page<NotificationHistoryDTO> legacyRBACGetEndpointHistory(final SecurityContext securityContext, final UriInfo uriInfo, final UUID id, final Boolean includeDetail, final Query query) {
return this.internalGetEndpointHistory(securityContext, uriInfo, id, includeDetail, query);
}

protected Page<NotificationHistoryDTO> internalGetEndpointHistory(final SecurityContext securityContext, final UriInfo uriInfo, final UUID id, final Boolean includeDetail, @Valid final Query query) {
if (!this.endpointRepository.existsByUuidAndOrgId(id, getOrgId(securityContext))) {
throw new NotFoundException("Endpoint not found");
}

String orgId = getOrgId(securityContext);
boolean doDetail = includeDetail != null && includeDetail;

final List<NotificationHistory> notificationHistory = this.notificationRepository.getNotificationHistory(orgId, id, doDetail, query);
final long notificationHistoryCount = this.notificationRepository.countNotificationHistoryElements(id, orgId);

return new Page<>(
commonMapper.notificationHistoryListToNotificationHistoryDTOList(notificationHistory),
PageLinksBuilder.build(uriInfo.getPath(), notificationHistoryCount, query.getLimit().getLimit(), query.getLimit().getOffset()),
new Meta(notificationHistoryCount)
);
}

@GET
@Path("/{id}")
@Produces(APPLICATION_JSON)
@Operation(summary = "Retrieve an endpoint", description = "Retrieves the public information associated with an endpoint such as its description, name, and properties.")
public EndpointDTO getEndpoint(@Context SecurityContext sec, @PathParam("id") UUID id) {
if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) {
this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW, id);

return this.internalGetEndpoint(sec, id, false);
} else {
return legacyGetEndpoint(sec, id, true);
}
}

@GET
@Produces(APPLICATION_JSON)
@Operation(summary = "List endpoints", description = "Provides a list of endpoints. Use this endpoint to find specific endpoints.")
@Parameters({
@Parameter(
name = "limit",
in = ParameterIn.QUERY,
description = "Number of items per page. If the value is 0, it will return all elements",
schema = @Schema(type = SchemaType.INTEGER)
),
@Parameter(
name = "pageNumber",
in = ParameterIn.QUERY,
description = "Page number. Starts at first page (0), if not specified starts at first page.",
schema = @Schema(type = SchemaType.INTEGER)
)
})
public EndpointPage getEndpoints(
@Context SecurityContext sec,
@BeanParam @Valid Query query,
@QueryParam("type") List<String> targetType,
@QueryParam("active") Boolean activeOnly,
@QueryParam("name") String name
) {
if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) {
// Fetch the set of integration IDs the user is authorized to view.
final Set<UUID> authorizedIds = this.kesselAuthorization.lookupAuthorizedIntegrations(sec, IntegrationPermission.VIEW);
if (authorizedIds.isEmpty()) {
Log.infof("[org_id: %s][username: %s] Kessel did not return any integration IDs for the request", getOrgId(sec), getUsername(sec));

return new EndpointPage(new ArrayList<>(), new HashMap<>(), new Meta(0L));
}

return internalGetEndpoints(sec, query, targetType, activeOnly, name, authorizedIds, true);
}

return getEndpointsLegacyRBACRoles(sec, query, targetType, activeOnly, name, true);
}
}

@GET
@Produces(APPLICATION_JSON)
@Operation(summary = "List endpoints", description = "Provides a list of endpoints. Use this endpoint to find specific endpoints.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.redhat.cloud.notifications.routers.handlers.endpoint;

import com.redhat.cloud.notifications.Constants;
import com.redhat.cloud.notifications.auth.ConsoleIdentityProvider;
import com.redhat.cloud.notifications.auth.kessel.permission.IntegrationPermission;
import com.redhat.cloud.notifications.db.Query;
import com.redhat.cloud.notifications.models.NotificationHistory;
import com.redhat.cloud.notifications.models.dto.v1.NotificationHistoryDTO;
import com.redhat.cloud.notifications.models.dto.v1.endpoint.EndpointDTO;
import com.redhat.cloud.notifications.routers.models.EndpointPage;
import com.redhat.cloud.notifications.routers.models.Meta;
import com.redhat.cloud.notifications.routers.models.Page;
import com.redhat.cloud.notifications.routers.models.PageLinksBuilder;
import io.quarkus.logging.Log;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.BeanParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.UriInfo;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameters;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import static com.redhat.cloud.notifications.db.repositories.NotificationRepository.MAX_NOTIFICATION_HISTORY_RESULTS;
import static com.redhat.cloud.notifications.routers.SecurityContextUtil.getOrgId;
import static com.redhat.cloud.notifications.routers.SecurityContextUtil.getUsername;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;

@Path(Constants.API_INTEGRATIONS_V_2_0 + "/endpoints")
public class EndpointResourceV2 extends EndpointResource {
@GET
@Path("/{id}/history")
@Produces(APPLICATION_JSON)
@Parameters(
{
@Parameter(
name = "limit",
in = ParameterIn.QUERY,
description = "Number of items per page, if not specified or 0 is used, returns a maximum of " + MAX_NOTIFICATION_HISTORY_RESULTS + " elements.",
schema = @Schema(type = SchemaType.INTEGER)
),
@Parameter(
name = "pageNumber",
in = ParameterIn.QUERY,
description = "Page number. Starts at first page (0), if not specified starts at first page.",
schema = @Schema(type = SchemaType.INTEGER)
),
@Parameter(
name = "includeDetail",
description = "Include the detail in the reply",
schema = @Schema(type = SchemaType.BOOLEAN)
)
}
)
public Page<NotificationHistoryDTO> getEndpointHistory(
@Context SecurityContext sec,
@Context UriInfo uriInfo,
@PathParam("id") UUID id,
@QueryParam("includeDetail") Boolean includeDetail,
@BeanParam Query query
) {
if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) {
this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW_HISTORY, id);

return this.internalGetEndpointHistory(sec, uriInfo, id, includeDetail, query);
} else {
return this.legacyRBACGetEndpointHistory(sec, uriInfo, id, includeDetail, query);
}
}

@RolesAllowed(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS)
protected Page<NotificationHistoryDTO> legacyRBACGetEndpointHistory(final SecurityContext securityContext, final UriInfo uriInfo, final UUID id, final Boolean includeDetail, final Query query) {
return this.internalGetEndpointHistory(securityContext, uriInfo, id, includeDetail, query);
}

protected Page<NotificationHistoryDTO> internalGetEndpointHistory(final SecurityContext securityContext, final UriInfo uriInfo, final UUID id, final Boolean includeDetail, @Valid final Query query) {
if (!this.endpointRepository.existsByUuidAndOrgId(id, getOrgId(securityContext))) {
throw new NotFoundException("Endpoint not found");
}

String orgId = getOrgId(securityContext);
boolean doDetail = includeDetail != null && includeDetail;

final List<NotificationHistory> notificationHistory = this.notificationRepository.getNotificationHistory(orgId, id, doDetail, query);
final long notificationHistoryCount = this.notificationRepository.countNotificationHistoryElements(id, orgId);

return new Page<>(
commonMapper.notificationHistoryListToNotificationHistoryDTOList(notificationHistory),
PageLinksBuilder.build(uriInfo.getPath(), notificationHistoryCount, query.getLimit().getLimit(), query.getLimit().getOffset()),
new Meta(notificationHistoryCount)
);
}

@GET
@Path("/{id}")
@Produces(APPLICATION_JSON)
@Operation(summary = "Retrieve an endpoint", description = "Retrieves the public information associated with an endpoint such as its description, name, and properties.")
public EndpointDTO getEndpoint(@Context SecurityContext sec, @PathParam("id") UUID id) {
if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) {
this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW, id);

return this.internalGetEndpoint(sec, id, false);
} else {
return legacyGetEndpoint(sec, id, true);
}
}

@GET
@Produces(APPLICATION_JSON)
@Operation(summary = "List endpoints", description = "Provides a list of endpoints. Use this endpoint to find specific endpoints.")
@Parameters(
{
@Parameter(
name = "limit",
in = ParameterIn.QUERY,
description = "Number of items per page. If the value is 0, it will return all elements",
schema = @Schema(type = SchemaType.INTEGER)
),
@Parameter(
name = "pageNumber",
in = ParameterIn.QUERY,
description = "Page number. Starts at first page (0), if not specified starts at first page.",
schema = @Schema(type = SchemaType.INTEGER)
)
}
)
public EndpointPage getEndpoints(
@Context SecurityContext sec,
@BeanParam @Valid Query query,
@QueryParam("type") List<String> targetType,
@QueryParam("active") Boolean activeOnly,
@QueryParam("name") String name
) {
if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) {
// Fetch the set of integration IDs the user is authorized to view.
final Set<UUID> authorizedIds = this.kesselAuthorization.lookupAuthorizedIntegrations(sec, IntegrationPermission.VIEW);
if (authorizedIds.isEmpty()) {
Log.infof("[org_id: %s][username: %s] Kessel did not return any integration IDs for the request", getOrgId(sec), getUsername(sec));

return new EndpointPage(new ArrayList<>(), new HashMap<>(), new Meta(0L));
}

return internalGetEndpoints(sec, query, targetType, activeOnly, name, authorizedIds, true);
}

return getEndpointsLegacyRBACRoles(sec, query, targetType, activeOnly, name, true);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.redhat.cloud.notifications.routers;
package com.redhat.cloud.notifications.routers.handlers.event;

import com.redhat.cloud.notifications.auth.kessel.KesselAuthorization;
import com.redhat.cloud.notifications.auth.kessel.permission.WorkspacePermission;
Expand Down Expand Up @@ -43,7 +43,6 @@
import java.util.stream.Collectors;

import static com.redhat.cloud.notifications.Constants.API_NOTIFICATIONS_V_1_0;
import static com.redhat.cloud.notifications.Constants.API_NOTIFICATIONS_V_2_0;
import static com.redhat.cloud.notifications.auth.ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS_EVENTS;
import static com.redhat.cloud.notifications.routers.SecurityContextUtil.getOrgId;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
Expand All @@ -66,11 +65,6 @@ public static class V1 extends EventResource {

}

@Path(API_NOTIFICATIONS_V_2_0 + "/notifications/events")
public static class V2 extends EventResource {

}

@GET
@Produces(APPLICATION_JSON)
@Operation(summary = "Retrieve the event log entries", description = "Retrieves the event log entries. Use this endpoint to review a full history of the events related to the tenant. You can sort by the bundle, application, event, and created fields. You can specify the sort order by appending :asc or :desc to the field, for example bundle:desc. Sorting defaults to desc for the created field and to asc for all other fields."
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.redhat.cloud.notifications.routers.handlers.event;

import jakarta.ws.rs.Path;

import static com.redhat.cloud.notifications.Constants.API_NOTIFICATIONS_V_2_0;

@Path(API_NOTIFICATIONS_V_2_0 + "/notifications/events")
public class EventResourceV2 extends EventResource {
}
Loading
Loading