Skip to content

Commit

Permalink
[MODAUD-194]. Implement consumer & endpoint for organization records
Browse files Browse the repository at this point in the history
  • Loading branch information
BKadirkhodjaev committed Nov 12, 2024
1 parent 8bde855 commit a16ec01
Show file tree
Hide file tree
Showing 36 changed files with 904 additions and 153 deletions.
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))
.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

0 comments on commit a16ec01

Please sign in to comment.