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

[MODAUD-194]. Implement consumer & endpoint for organization records #178

Merged
merged 3 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
23 changes: 22 additions & 1 deletion descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,21 @@
}
]
},
{
"id": "acquisition-organization-events",
"version": "1.0",
"handlers": [
{
"methods": [
"GET"
],
"pathPattern": "/audit-data/acquisition/organization/{id}",
"permissionsRequired": [
"acquisition.organization.events.get"
]
}
]
},
{
"id": "circulation-logs",
"version": "1.2",
Expand Down Expand Up @@ -304,6 +319,11 @@
"displayName": "Acquisition invoice-line events - get invoice-line change events",
"description": "Get invoice-line change events"
},
{
"permissionName": "acquisition.organization.events.get",
"displayName": "Acquisition organization events - get organization change events",
"description": "Get organization change events"
},
{
"permissionName": "audit.all",
"displayName": "Audit - all permissions",
Expand All @@ -320,7 +340,8 @@
"acquisition.piece.events.get",
"acquisition.piece.events.history.get",
"acquisition.invoice.events.get",
"acquisition.invoice-line.events.get"
"acquisition.invoice-line.events.get",
"acquisition.organization.events.get"
]
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ public interface InvoiceEventsDao {
*
* @param invoiceId invoice id
* @param sortBy sort by
* @param sortInvoice sort invoice
* @param sortOrder sort order
* @param limit limit
* @param offset offset
* @param tenantId tenant id
* @return future with InvoiceAuditEventCollection
*/
Future<InvoiceAuditEventCollection> getAuditEventsByInvoiceId(String invoiceId, String sortBy, String sortInvoice, int limit, int offset, String tenantId);
Future<InvoiceAuditEventCollection> getAuditEventsByInvoiceId(String invoiceId, String sortBy, String sortOrder, int limit, int offset, String tenantId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.folio.dao.acquisition;

import io.vertx.core.Future;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import org.folio.rest.jaxrs.model.OrganizationAuditEvent;
import org.folio.rest.jaxrs.model.OrganizationAuditEventCollection;

public interface OrganizationEventsDao {

/**
* Saves organizationAuditEvent entity to DB
*
* @param organizationAuditEvent OrganizationAuditEvent entity to save
* @param tenantId tenant id
* @return future with created row
*/
Future<RowSet<Row>> save(OrganizationAuditEvent organizationAuditEvent, String tenantId);

/**
* Searches for organization audit events by id
*
* @param organizationId organization id
* @param sortBy sort by
* @param sortOrder sort order
* @param limit limit
* @param offset offset
* @param tenantId tenant id
* @return future with OrganizationAuditEventCollection
*/
Future<OrganizationAuditEventCollection> getAuditEventsByOrganizationId(String organizationId, String sortBy, String sortOrder, int limit, int offset, String tenantId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ public Future<InvoiceAuditEventCollection> getAuditEventsByInvoiceId(String invo
String logTable = formatDBTableName(tenantId, TABLE_NAME);
String query = format(GET_BY_INVOICE_ID_SQL, logTable, logTable, format(ORDER_BY_PATTERN, sortBy, sortOrder));
return pgClientFactory.createInstance(tenantId).execute(query, Tuple.of(UUID.fromString(invoiceId), limit, offset))
.map(rowSet -> rowSet.rowCount() == 0 ? new InvoiceAuditEventCollection().withTotalItems(0)
: mapRowToListOfInvoiceEvent(rowSet));
.map(this::mapRowToListOfInvoiceEvent);
}

private Future<RowSet<Row>> makeSaveCall(String query, InvoiceAuditEvent invoiceAuditEvent, String tenantId) {
Expand All @@ -88,6 +87,9 @@ private Future<RowSet<Row>> makeSaveCall(String query, InvoiceAuditEvent invoice

private InvoiceAuditEventCollection mapRowToListOfInvoiceEvent(RowSet<Row> rowSet) {
LOGGER.debug("mapRowToListOfInvoiceEvent:: Mapping row to List of Invoice Events");
if (rowSet.rowCount() == 0) {
return new InvoiceAuditEventCollection().withTotalItems(0);
}
InvoiceAuditEventCollection invoiceAuditEventCollection = new InvoiceAuditEventCollection();
rowSet.iterator().forEachRemaining(row -> {
invoiceAuditEventCollection.getInvoiceAuditEvents().add(mapRowToInvoiceEvent(row));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ public Future<InvoiceLineAuditEventCollection> getAuditEventsByInvoiceLineId(Str
String logTable = formatDBTableName(tenantId, TABLE_NAME);
String query = format(GET_BY_INVOICE_LINE_ID_SQL, logTable, logTable, format(ORDER_BY_PATTERN, sortBy, sortOrder));
return pgClientFactory.createInstance(tenantId).execute(query, Tuple.of(UUID.fromString(invoiceLineId), limit, offset))
.map(rowSet -> rowSet.rowCount() == 0 ? new InvoiceLineAuditEventCollection().withTotalItems(0)
: mapRowToListOfInvoiceLineEvent(rowSet));
.map(this::mapRowToListOfInvoiceLineEvent);
}

private Future<RowSet<Row>> makeSaveCall(String query, InvoiceLineAuditEvent invoiceLineAuditEvent, String tenantId) {
Expand All @@ -91,6 +90,9 @@ private Future<RowSet<Row>> makeSaveCall(String query, InvoiceLineAuditEvent inv

private InvoiceLineAuditEventCollection mapRowToListOfInvoiceLineEvent(RowSet<Row> rowSet) {
LOGGER.debug("mapRowToListOfInvoiceLineEvent:: Mapping row to List of Invoice Line Events");
if (rowSet.rowCount() == 0) {
return new InvoiceLineAuditEventCollection().withTotalItems(0);
}
InvoiceLineAuditEventCollection invoiceLineAuditEventCollection = new InvoiceLineAuditEventCollection();
rowSet.iterator().forEachRemaining(row -> {
invoiceLineAuditEventCollection.getInvoiceLineAuditEvents().add(mapRowToInvoiceLineEvent(row));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ public Future<OrderAuditEventCollection> getAuditEventsByOrderId(String orderId,
promise.fail(e);
}
LOGGER.info("getAuditEventsByOrderId:: Retrieved AuditEvent with order id : {}", orderId);
return promise.future().map(rowSet -> rowSet.rowCount() == 0 ? new OrderAuditEventCollection().withTotalItems(0)
: mapRowToListOfOrderEvent(rowSet));
return promise.future().map(this::mapRowToListOfOrderEvent);
}

private void makeSaveCall(Promise<RowSet<Row>> promise, String query, OrderAuditEvent orderAuditEvent, String tenantId) {
Expand All @@ -102,6 +101,9 @@ private void makeSaveCall(Promise<RowSet<Row>> promise, String query, OrderAudit

private OrderAuditEventCollection mapRowToListOfOrderEvent(RowSet<Row> rowSet) {
LOGGER.debug("mapRowToListOfOrderEvent:: Mapping row to List of Order Events");
if (rowSet.rowCount() == 0) {
return new OrderAuditEventCollection().withTotalItems(0);
}
OrderAuditEventCollection orderAuditEventCollection = new OrderAuditEventCollection();
rowSet.iterator().forEachRemaining(row -> {
orderAuditEventCollection.getOrderAuditEvents().add(mapRowToOrderEvent(row));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ public Future<OrderLineAuditEventCollection> getAuditEventsByOrderLineId(String
}

LOGGER.info("getAuditEventsByOrderLineId:: Retrieved AuditEvent with order line id : {}", orderLineId);
return promise.future().map(rowSet -> rowSet.rowCount() == 0 ? new OrderLineAuditEventCollection().withTotalItems(0)
: mapRowToListOfOrderLineEvent(rowSet));
return promise.future().map(this::mapRowToListOfOrderLineEvent);
}

private void makeSaveCall(Promise<RowSet<Row>> promise, String query, OrderLineAuditEvent orderLineAuditEvent, String tenantId) {
Expand All @@ -105,6 +104,9 @@ private void makeSaveCall(Promise<RowSet<Row>> promise, String query, OrderLineA

private OrderLineAuditEventCollection mapRowToListOfOrderLineEvent(RowSet<Row> rowSet) {
LOGGER.debug("mapRowToListOfOrderLineEvent:: Mapping row to List of Order Line Events");
if (rowSet.rowCount() == 0) {
return new OrderLineAuditEventCollection().withTotalItems(0);
}
OrderLineAuditEventCollection orderLineAuditEventCollection = new OrderLineAuditEventCollection();
rowSet.iterator().forEachRemaining(row -> {
orderLineAuditEventCollection.getOrderLineAuditEvents().add(mapRowToOrderLineEvent(row));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package org.folio.dao.acquisition.impl;

import io.vertx.core.Future;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import io.vertx.sqlclient.Tuple;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.dao.acquisition.OrganizationEventsDao;
import org.folio.rest.jaxrs.model.OrganizationAuditEvent;
import org.folio.rest.jaxrs.model.OrganizationAuditEventCollection;
import org.folio.util.PostgresClientFactory;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.UUID;

import static java.lang.String.format;
import static org.folio.util.AuditEventDBConstants.ACTION_DATE_FIELD;
import static org.folio.util.AuditEventDBConstants.ACTION_FIELD;
import static org.folio.util.AuditEventDBConstants.EVENT_DATE_FIELD;
import static org.folio.util.AuditEventDBConstants.ID_FIELD;
import static org.folio.util.AuditEventDBConstants.MODIFIED_CONTENT_FIELD;
import static org.folio.util.AuditEventDBConstants.ORDER_BY_PATTERN;
import static org.folio.util.AuditEventDBConstants.ORGANIZATION_ID_FIELD;
import static org.folio.util.AuditEventDBConstants.TOTAL_RECORDS_FIELD;
import static org.folio.util.AuditEventDBConstants.USER_ID_FIELD;
import static org.folio.util.DbUtils.formatDBTableName;

@Repository
public class OrganizationEventsDaoImpl implements OrganizationEventsDao {

private static final Logger LOGGER = LogManager.getLogger();

public static final String TABLE_NAME = "acquisition_organization_log";

public static final String GET_BY_INVOICE_ID_SQL = "SELECT id, action, organization_id, user_id, event_date, action_date, modified_content_snapshot," +
" (SELECT count(*) AS total_records FROM %s WHERE organization_id = $1) FROM %s WHERE organization_id = $1 %s LIMIT $2 OFFSET $3";

public static final String INSERT_SQL = "INSERT INTO %s (id, action, organization_id, user_id, event_date, action_date, modified_content_snapshot)" +
" VALUES ($1, $2, $3, $4, $5, $6, $7)";

private final PostgresClientFactory pgClientFactory;

public OrganizationEventsDaoImpl(PostgresClientFactory pgClientFactory) {
this.pgClientFactory = pgClientFactory;
}

@Override
public Future<RowSet<Row>> save(OrganizationAuditEvent organizationAuditEvent, String tenantId) {
LOGGER.debug("save:: Saving Organization AuditEvent with tenant id : {}", tenantId);
String logTable = formatDBTableName(tenantId, TABLE_NAME);
String query = format(INSERT_SQL, logTable);
return makeSaveCall(query, organizationAuditEvent, tenantId)
.onSuccess(rows -> LOGGER.info("save:: Saved Organization AuditEvent with tenant id : {}", tenantId))
SerhiiNosko marked this conversation as resolved.
Show resolved Hide resolved
.onFailure(e -> LOGGER.error("Failed to save record with id: {} for organization id: {} in to table {}",
organizationAuditEvent.getId(), organizationAuditEvent.getOrganizationId(), TABLE_NAME, e));
}

@Override
public Future<OrganizationAuditEventCollection> getAuditEventsByOrganizationId(String organizationId, String sortBy, String sortOrder, int limit, int offset, String tenantId) {
LOGGER.debug("getAuditEventsByOrganizationId:: Retrieving AuditEvent with organization id : {}", organizationId);
String logTable = formatDBTableName(tenantId, TABLE_NAME);
String query = format(GET_BY_INVOICE_ID_SQL, logTable, logTable, format(ORDER_BY_PATTERN, sortBy, sortOrder));
return pgClientFactory.createInstance(tenantId).execute(query, Tuple.of(UUID.fromString(organizationId), limit, offset))
.map(this::mapRowToListOfOrganizationEvent);
}

private Future<RowSet<Row>> makeSaveCall(String query, OrganizationAuditEvent organizationAuditEvent, String tenantId) {
LOGGER.debug("makeSaveCall:: Making save call with query : {} and tenant id : {}", query, tenantId);
try {
return pgClientFactory.createInstance(tenantId).execute(query, Tuple.of(organizationAuditEvent.getId(),
organizationAuditEvent.getAction(),
organizationAuditEvent.getOrganizationId(),
organizationAuditEvent.getUserId(),
LocalDateTime.ofInstant(organizationAuditEvent.getEventDate().toInstant(), ZoneId.systemDefault()),
LocalDateTime.ofInstant(organizationAuditEvent.getActionDate().toInstant(), ZoneId.systemDefault()),
JsonObject.mapFrom(organizationAuditEvent.getOrganizationSnapshot())));
} catch (Exception e) {
return Future.failedFuture(e);
}
}

private OrganizationAuditEventCollection mapRowToListOfOrganizationEvent(RowSet<Row> rowSet) {
LOGGER.debug("mapRowToListOfOrganizationEvent:: Mapping row to List of Organization Events");
if (rowSet.rowCount() == 0) {
return new OrganizationAuditEventCollection().withTotalItems(0);
}
OrganizationAuditEventCollection organizationAuditEventCollection = new OrganizationAuditEventCollection();
rowSet.iterator().forEachRemaining(row -> {
organizationAuditEventCollection.getOrganizationAuditEvents().add(mapRowToOrganizationEvent(row));
organizationAuditEventCollection.setTotalItems(row.getInteger(TOTAL_RECORDS_FIELD));
});
LOGGER.debug("mapRowToListOfOrganizationEvent:: Mapped row to List of Organization Events");
return organizationAuditEventCollection;
}

private OrganizationAuditEvent mapRowToOrganizationEvent(Row row) {
LOGGER.debug("mapRowToOrganizationEvent:: Mapping row to Organization Event");
return new OrganizationAuditEvent()
.withId(row.getValue(ID_FIELD).toString())
.withAction(row.get(OrganizationAuditEvent.Action.class, ACTION_FIELD))
.withOrganizationId(row.getValue(ORGANIZATION_ID_FIELD).toString())
.withUserId(row.getValue(USER_ID_FIELD).toString())
.withEventDate(Date.from(row.getLocalDateTime(EVENT_DATE_FIELD).toInstant(ZoneOffset.UTC)))
.withActionDate(Date.from(row.getLocalDateTime(ACTION_DATE_FIELD).toInstant(ZoneOffset.UTC)))
.withOrganizationSnapshot(JsonObject.mapFrom(row.getValue(MODIFIED_CONTENT_FIELD)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,7 @@ public Future<PieceAuditEventCollection> getAuditEventsByPieceId(String pieceId,
promise.fail(e);
}
LOGGER.info("getAuditEventsByOrderId:: Retrieved AuditEvent with piece id : {}", pieceId);
return promise.future().map(rowSet -> rowSet.rowCount() == 0 ?
new PieceAuditEventCollection().withTotalItems(0) :
mapRowToListOfPieceEvent(rowSet));
return promise.future().map(this::mapRowToListOfPieceEvent);
}

@Override
Expand All @@ -114,12 +112,14 @@ public Future<PieceAuditEventCollection> getAuditEventsWithStatusChangesByPieceI
promise.fail(e);
}
LOGGER.info("getAuditEventsByOrderId:: Retrieved AuditEvent with piece id: {}", pieceId);
return promise.future().map(rowSet -> rowSet.rowCount() == 0 ? new PieceAuditEventCollection().withTotalItems(0)
: mapRowToListOfPieceEvent(rowSet));
return promise.future().map(this::mapRowToListOfPieceEvent);
}

private PieceAuditEventCollection mapRowToListOfPieceEvent(RowSet<Row> rowSet) {
LOGGER.debug("mapRowToListOfOrderEvent:: Mapping row to List of Piece Events");
if (rowSet.rowCount() == 0) {
return new PieceAuditEventCollection().withTotalItems(0);
}
PieceAuditEventCollection pieceAuditEventCollection = new PieceAuditEventCollection();
rowSet.iterator().forEachRemaining(row -> {
pieceAuditEventCollection.getPieceAuditEvents().add(mapRowToPieceEvent(row));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.folio.rest.jaxrs.model.AuditDataAcquisitionInvoiceLineIdGetSortOrder;
import org.folio.rest.jaxrs.model.AuditDataAcquisitionOrderIdGetSortOrder;
import org.folio.rest.jaxrs.model.AuditDataAcquisitionOrderLineIdGetSortOrder;
import org.folio.rest.jaxrs.model.AuditDataAcquisitionOrganizationIdGetSortOrder;
import org.folio.rest.jaxrs.model.AuditDataAcquisitionPieceIdGetSortOrder;
import org.folio.rest.jaxrs.model.AuditDataAcquisitionPieceIdStatusChangeHistoryGetSortOrder;
import org.folio.rest.jaxrs.resource.AuditDataAcquisition;
Expand All @@ -19,6 +20,7 @@
import org.folio.services.acquisition.InvoiceLineAuditEventsService;
import org.folio.services.acquisition.OrderAuditEventsService;
import org.folio.services.acquisition.OrderLineAuditEventsService;
import org.folio.services.acquisition.OrganizationAuditEventsService;
import org.folio.services.acquisition.PieceAuditEventsService;
import org.folio.spring.SpringContextUtil;
import org.folio.util.ErrorUtils;
Expand All @@ -43,6 +45,8 @@ public class AuditDataAcquisitionImpl implements AuditDataAcquisition {
private InvoiceAuditEventsService invoiceAuditEventsService;
@Autowired
private InvoiceLineAuditEventsService invoiceLineAuditEventsService;
@Autowired
private OrganizationAuditEventsService organizationAuditEventsService;

public AuditDataAcquisitionImpl() {
SpringContextUtil.autowireDependencies(this, Vertx.currentContext());
Expand Down Expand Up @@ -131,7 +135,7 @@ public void getAuditDataAcquisitionInvoiceById(String invoiceId, String sortBy,
.otherwise(this::mapExceptionToResponse)
.onComplete(asyncResultHandler);
} catch (Exception e) {
LOGGER.error("Failed to get invoice audit events by piece id: {}", invoiceId, e);
LOGGER.error("Failed to get invoice audit events by invoice id: {}", invoiceId, e);
asyncResultHandler.handle(Future.succeededFuture(mapExceptionToResponse(e)));
}
}
Expand All @@ -148,7 +152,25 @@ public void getAuditDataAcquisitionInvoiceLineById(String invoiceLineId, String
.otherwise(this::mapExceptionToResponse)
.onComplete(asyncResultHandler);
} catch (Exception e) {
LOGGER.error("Failed to get invoice line audit events by order line id: {}", invoiceLineId, e);
LOGGER.error("Failed to get invoice line audit events by invoice line id: {}", invoiceLineId, e);
asyncResultHandler.handle(Future.succeededFuture(mapExceptionToResponse(e)));
}
}

@Override
public void getAuditDataAcquisitionOrganizationById(String organizationId, String sortBy,
AuditDataAcquisitionOrganizationIdGetSortOrder sortOrder,
int limit, int offset, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
LOGGER.debug("getAuditDataAcquisitionOrganizationById:: Retrieving Audit Data Acquisition Organization By Id : {}", organizationId);
String tenantId = TenantTool.tenantId(okapiHeaders);
try {
organizationAuditEventsService.getAuditEventsByOrganizationId(organizationId, sortBy, sortOrder.name(), limit, offset, tenantId)
.map(GetAuditDataAcquisitionOrganizationByIdResponse::respond200WithApplicationJson)
.map(Response.class::cast)
.otherwise(this::mapExceptionToResponse)
.onComplete(asyncResultHandler);
} catch (Exception e) {
LOGGER.error("Failed to get organization audit events by organization id: {}", organizationId, e);
asyncResultHandler.handle(Future.succeededFuture(mapExceptionToResponse(e)));
}
}
Expand Down
Loading