MNT-22485: audit query with createdAt criteria returns correct totalI… (#1535)

* MNT-22485: audit query with createdAt criteria returns correct totalItems
This commit is contained in:
Vítor Moreira
2022-11-09 15:58:49 +00:00
committed by GitHub
parent 759927c37b
commit 14572d328f
10 changed files with 237 additions and 104 deletions

View File

@@ -295,7 +295,18 @@ public class AuditImpl implements Audit
} }
else else
{ {
totalItems = hasMoreItems ? getAuditEntriesCountByApp(auditApplication) : totalRetrievedItems; if (hasMoreItems) {
if (q != null) {
// filtering via "where" clause
AuditEntryQueryWalker propertyWalker = new AuditEntryQueryWalker();
QueryHelper.walk(q, propertyWalker);
totalItems = getAuditEntriesCountByAppAndProperties(auditApplication, propertyWalker);
} else {
totalItems = getAuditEntriesCountByApp(auditApplication);
}
} else {
totalItems = totalRetrievedItems;
}
} }
entriesAudit = (skipCount >= totalRetrievedItems) entriesAudit = (skipCount >= totalRetrievedItems)
@@ -895,4 +906,19 @@ public class AuditImpl implements Audit
final String applicationName = auditApplication.getKey().substring(1); final String applicationName = auditApplication.getKey().substring(1);
return auditService.getAuditEntriesCountByApp(applicationName); return auditService.getAuditEntriesCountByApp(applicationName);
} }
public int getAuditEntriesCountByAppAndProperties(AuditService.AuditApplication auditApplication, AuditEntryQueryWalker propertyWalker)
{
final String applicationName = auditApplication.getKey().substring(1);
AuditQueryParameters parameters = new AuditQueryParameters();
parameters.setApplicationName(applicationName);
parameters.setFromTime(propertyWalker.getFromTime());
parameters.setToTime(propertyWalker.getToTime());
parameters.setFromId(propertyWalker.getFromId());
parameters.setToId(propertyWalker.getToId());
parameters.setUser(propertyWalker.getCreatedByUser());
return auditService.getAuditEntriesCountByAppAndProperties(applicationName, parameters);
}
} }

View File

@@ -34,6 +34,9 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.net.URL; import java.net.URL;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -386,6 +389,7 @@ public class AuditAppTest extends AbstractSingleNetworkSiteTest
AuditApp auditApp = auditAppsProxy.getAuditApp("alfresco-access"); AuditApp auditApp = auditAppsProxy.getAuditApp("alfresco-access");
testGetAuditEntries(auditAppsProxy, auditApp); testGetAuditEntries(auditAppsProxy, auditApp);
testGetAuditEntriesWhereCreatedAt(auditAppsProxy, auditApp);
testAuditEntriesSorting(auditAppsProxy, auditApp); testAuditEntriesSorting(auditAppsProxy, auditApp);
testAuditEntriesWhereDate(auditAppsProxy, auditApp); testAuditEntriesWhereDate(auditAppsProxy, auditApp);
testAuditEntriesWhereId(auditAppsProxy, auditApp); testAuditEntriesWhereId(auditAppsProxy, auditApp);
@@ -396,6 +400,30 @@ public class AuditAppTest extends AbstractSingleNetworkSiteTest
testDeleteAuditEntries(auditAppsProxy, auditApp); testDeleteAuditEntries(auditAppsProxy, auditApp);
} }
private void testGetAuditEntriesWhereCreatedAt(AuditApps auditAppsProxy, AuditApp auditApp) throws Exception
{
// get "totalItems" for a specific time interval
Map<String, String> params = new HashMap<>();
final ZonedDateTime beginDate = ZonedDateTime.now().minusHours(1).truncatedTo(ChronoUnit.MINUTES);
final ZonedDateTime endDate = ZonedDateTime.now().truncatedTo(ChronoUnit.MINUTES);
params.put("where","(createdAt BETWEEN ('"+beginDate.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)+"' , '"+endDate.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)+"'))");
ListResponse<AuditEntry> auditEntries = auditAppsProxy.getAuditAppEntries(auditApp.getId(), params,
HttpServletResponse.SC_OK);
int totalItemsWithDefaultMaxSize = auditEntries.getPaging().getTotalItems();
assertTrue( totalItemsWithDefaultMaxSize > 1 );
// get "totalItems" for a specific time internal (with maxSize=1)
params.put("maxSize","1");
auditEntries = auditAppsProxy.getAuditAppEntries(auditApp.getId(), params,
HttpServletResponse.SC_OK);
int totalItemsWithMaxSize1 = auditEntries.getPaging().getTotalItems();
// number of "totalItems" must be the same, regardless maxSize
assertEquals(totalItemsWithMaxSize1, totalItemsWithDefaultMaxSize);
}
private void testGetAuditEntries(AuditApps auditAppsProxy, AuditApp auditApp) throws Exception private void testGetAuditEntries(AuditApps auditAppsProxy, AuditApp auditApp) throws Exception
{ {
// Positive tests // Positive tests

View File

@@ -272,4 +272,16 @@ public interface AuditComponent
{ {
return -1; return -1;
} }
/**
* Issue an audit query to retrieve count of records for a given application and properties
*
* @param applicationName the name of the application
* @param parameters audit parameters provided by the <code>where</code> clause on the ReST API
* @return a map containing min/max and the associated value
*/
default int getAuditEntriesCountByAppAndProperties(String applicationName, AuditQueryParameters parameters)
{
return -1;
}
} }

View File

@@ -955,4 +955,11 @@ public class AuditComponentImpl implements AuditComponent
return auditDAO.getAuditEntriesCountByApp(applicationId); return auditDAO.getAuditEntriesCountByApp(applicationId);
} }
@Override public int getAuditEntriesCountByAppAndProperties(String applicationName, AuditQueryParameters parameters)
{
org.alfresco.repo.domain.audit.AuditQueryParameters dbParameters = new org.alfresco.repo.domain.audit.AuditQueryParameters();
return auditDAO.getAuditEntriesCountByAppAndProperties(applicationName, parameters);
}
} }

View File

@@ -186,4 +186,12 @@ public class AuditServiceImpl implements AuditService
{ {
return auditComponent.getAuditEntriesCountByApp(applicationName); return auditComponent.getAuditEntriesCountByApp(applicationName);
} }
/**
* {@inheritDoc}
*/
@Override public int getAuditEntriesCountByAppAndProperties(String applicationName, AuditQueryParameters parameters)
{
return auditComponent.getAuditEntriesCountByAppAndProperties(applicationName, parameters);
}
} }

View File

@@ -452,37 +452,86 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
org.alfresco.service.cmr.audit.AuditQueryParameters parameters, org.alfresco.service.cmr.audit.AuditQueryParameters parameters,
int maxResults) int maxResults)
{ {
String searchKey = null;
Serializable searchValue = null;
if (parameters.getSearchKeyValues().size() > 0)
{
// Only handle one pair for now
Pair<String, Serializable> searchKeyValue = parameters.getSearchKeyValues().get(0);
searchKey = searchKeyValue.getFirst();
searchValue = searchKeyValue.getSecond();
}
AuditQueryRowHandler rowHandler = new AuditQueryRowHandler(callback); AuditQueryRowHandler rowHandler = new AuditQueryRowHandler(callback);
findAuditEntries( findAuditEntries(
rowHandler, rowHandler,
parameters.isForward(),
parameters.getApplicationName(),
parameters.getUser(),
parameters.getFromId(),
parameters.getToId(),
parameters.getFromTime(),
parameters.getToTime(),
maxResults, maxResults,
searchKey, parameters);
searchValue);
} }
protected abstract void findAuditEntries( protected abstract void findAuditEntries(
AuditQueryRowHandler rowHandler, AuditQueryRowHandler rowHandler,
boolean forward,
String applicationName, String user,
Long fromId, Long toId,
Long fromTime, Long toTime,
int maxResults, int maxResults,
String searchKey, Serializable searchValue); org.alfresco.service.cmr.audit.AuditQueryParameters restParameters);
protected AuditQueryParameters convertFromRestAuditQueryParameters(org.alfresco.service.cmr.audit.AuditQueryParameters restParameters)
{
AuditQueryParameters dbParameters = new AuditQueryParameters();
String appName = restParameters.getApplicationName();
if (appName != null)
{
// Look up the application's ID (this is unique)
Pair<Long, Serializable> appNamePair = propertyValueDAO.getPropertyValue(appName);
if (appNamePair == null)
{
// No such value
return null;
}
dbParameters.setAuditAppNameId(appNamePair.getFirst());
}
String user = restParameters.getUser();
if (user != null)
{
// Look up the application's ID (this is unique)
Pair<Long, Serializable> userPair = propertyValueDAO.getPropertyValue(user);
if (userPair == null)
{
// No such value
return null;
}
dbParameters.setAuditUserId(userPair.getFirst());
}
dbParameters.setAuditFromId(restParameters.getFromId());
dbParameters.setAuditToId(restParameters.getToId());
dbParameters.setAuditFromTime(restParameters.getFromTime());
dbParameters.setAuditToTime(restParameters.getToTime());
String searchKey = null;
Serializable searchValue = null;
if (restParameters.getSearchKeyValues().size() > 0)
{
// Only handle one pair for now
Pair<String, Serializable> searchKeyValue = restParameters.getSearchKeyValues().get(0);
searchKey = searchKeyValue.getFirst();
searchValue = searchKeyValue.getSecond();
}
if (searchKey != null)
{
// Look up the ID of the search key
Pair<Long, Serializable> searchKeyPair = propertyValueDAO.getPropertyValue(searchKey);
if (searchKeyPair == null)
{
// No such value
return null;
}
dbParameters.setSearchKeyId(searchKeyPair.getFirst());
}
if (searchValue != null)
{
// Look up the ID of the search key
Pair<Long, Serializable> searchValuePair = propertyValueDAO.getPropertyValue(searchValue);
if (searchValuePair == null)
{
// No such value
return null;
}
dbParameters.setSearchValueId(searchValuePair.getFirst());
}
dbParameters.setForward(restParameters.isForward());
return dbParameters;
}
} }

View File

@@ -244,4 +244,16 @@ public interface AuditDAO
{ {
return -1; return -1;
} }
/**
* Issue an audit query to retrieve count of records for a given application and properties
*
* @param applicationName name of the application to be queried
* @param parameters audit parameters provided by the <code>where</code> clause on the ReST API
* @return a map containing min/max and the associated value
*/
default int getAuditEntriesCountByAppAndProperties(String applicationName, org.alfresco.service.cmr.audit.AuditQueryParameters parameters)
{
return -1;
}
} }

View File

@@ -66,6 +66,7 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
private static final String INSERT_ENTRY = "alfresco.audit.insert.insert_AuditEntry"; private static final String INSERT_ENTRY = "alfresco.audit.insert.insert_AuditEntry";
private static final String SELECT_MINMAX_ENTRY_FOR_APP = "alfresco.audit.select_MinMaxAuditEntryId"; private static final String SELECT_MINMAX_ENTRY_FOR_APP = "alfresco.audit.select_MinMaxAuditEntryId";
private static final String SELECT_COUNT_ENTRIES_FOR_APP = "alfresco.audit.select_CountAuditEntryId"; private static final String SELECT_COUNT_ENTRIES_FOR_APP = "alfresco.audit.select_CountAuditEntryId";
private static final String SELECT_COUNT_ENTRIES_FOR_APP_WITH_PROPERTIES = "select_CountAuditEntryIdWithWhereClause";
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final String SELECT_ENTRIES_SIMPLE = "alfresco.audit.select_AuditEntriesSimple"; private static final String SELECT_ENTRIES_SIMPLE = "alfresco.audit.select_AuditEntriesSimple";
@@ -235,67 +236,28 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
return result; return result;
} }
@Override
public int getAuditEntriesCountByAppAndProperties(String applicationName, org.alfresco.service.cmr.audit.AuditQueryParameters parameters)
{
AuditQueryParameters dbParameters = convertFromRestAuditQueryParameters(parameters);
int result = template.selectOne(SELECT_COUNT_ENTRIES_FOR_APP_WITH_PROPERTIES, dbParameters);
return result;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
protected void findAuditEntries( protected void findAuditEntries(
final AuditQueryRowHandler rowHandler, final AuditQueryRowHandler rowHandler,
boolean forward,
String appName, String user,
Long fromId, Long toId,
Long fromTime, Long toTime,
int maxResults, int maxResults,
String searchKey, Serializable searchValue) org.alfresco.service.cmr.audit.AuditQueryParameters restParameters)
{ {
AuditQueryParameters params = new AuditQueryParameters(); AuditQueryParameters params = convertFromRestAuditQueryParameters(restParameters);
if (appName != null) if (params==null)
{ {
// Look up the application's ID (this is unique)
Pair<Long, Serializable> appNamePair = propertyValueDAO.getPropertyValue(appName);
if (appNamePair == null)
{
// No such value
return; return;
} }
params.setAuditAppNameId(appNamePair.getFirst());
}
if (user != null)
{
// Look up the application's ID (this is unique)
Pair<Long, Serializable> userPair = propertyValueDAO.getPropertyValue(user);
if (userPair == null)
{
// No such value
return;
}
params.setAuditUserId(userPair.getFirst());
}
params.setAuditFromId(fromId);
params.setAuditToId(toId);
params.setAuditFromTime(fromTime);
params.setAuditToTime(toTime);
if (searchKey != null)
{
// Look up the ID of the search key
Pair<Long, Serializable> searchKeyPair = propertyValueDAO.getPropertyValue(searchKey);
if (searchKeyPair == null)
{
// No such value
return;
}
params.setSearchKeyId(searchKeyPair.getFirst());
}
if (searchValue != null)
{
// Look up the ID of the search key
Pair<Long, Serializable> searchValuePair = propertyValueDAO.getPropertyValue(searchValue);
if (searchValuePair == null)
{
// No such value
return;
}
params.setSearchValueId(searchValuePair.getFirst());
}
params.setForward(forward);
if (maxResults > 0) if (maxResults > 0)
{ {

View File

@@ -252,4 +252,16 @@ public interface AuditService
{ {
return -1; return -1;
} }
/**
* Issue an audit query to retrieve min / max audit record id for a given application and properties
*
* @param applicationName the name of the application
* @param parameters audit parameters provided by the <code>where</code> clause on the ReST API
* @return a map containing min/max and the associated value
*/
default int getAuditEntriesCountByAppAndProperties(String applicationName, AuditQueryParameters parameters)
{
return -1;
}
} }

View File

@@ -50,6 +50,15 @@
<!-- Parameter Maps --> <!-- Parameter Maps -->
<!-- --> <!-- -->
<parameterMap id="parameter_AuditAppId_WhereClauseMap" type="map">
<parameter property="auditAppNameId" jdbcType="BIGINT" javaType="Long"/>
<parameter property="auditUserId" jdbcType="BIGINT" javaType="Long"/>
<parameter property="auditFromTime" jdbcType="BIGINT" javaType="Long"/>
<parameter property="auditToTime" jdbcType="BIGINT" javaType="Long"/>
<parameter property="auditFromId" jdbcType="BIGINT" javaType="Long"/>
<parameter property="auditToId" jdbcType="BIGINT" javaType="Long"/>
</parameterMap>
<parameterMap id="parameter_IdMap" type="map"> <parameterMap id="parameter_IdMap" type="map">
<parameter property="id" jdbcType="BIGINT" javaType="java.lang.Long"/> <parameter property="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
</parameterMap> </parameterMap>
@@ -291,6 +300,14 @@
alf_audit_entry.audit_app_id = #{auditAppId} alf_audit_entry.audit_app_id = #{auditAppId}
</select> </select>
<select id="select_CountAuditEntryIdWithWhereClause" parameterMap="parameter_AuditAppId_WhereClauseMap" resultType="int">
select
COUNT(id)
from
alf_audit_entry as entry
<include refid="select_AuditEntriesWhereSnippet"/>
</select>
<!-- Get the maximum/minimum audit entry id for application --> <!-- Get the maximum/minimum audit entry id for application -->
<select id="select_MinMaxAuditEntryId" parameterMap="parameter_IdMinMaxMap" resultMap="result_minMaxMap"> <select id="select_MinMaxAuditEntryId" parameterMap="parameter_IdMinMaxMap" resultMap="result_minMaxMap">
select select