mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-17 20:50:44 +00:00
Remove single-parent concept on app-children; more working version of recordLock from join
This commit is contained in:
@ -25,7 +25,6 @@ package com.kingsrook.qqq.backend.core.actions.permissions;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
@ -121,7 +120,7 @@ public class PermissionsHelper
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// if the entity just has a 'has access', then check for 'has access' //
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, PrivatePermissionSubType.HAS_ACCESS);
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, metaDataWithPermissionRules, PrivatePermissionSubType.HAS_ACCESS);
|
||||
}
|
||||
case READ_WRITE_PERMISSIONS:
|
||||
{
|
||||
@ -130,9 +129,9 @@ public class PermissionsHelper
|
||||
////////////////////////////////////////////////////////////////
|
||||
if(metaDataWithPermissionRules instanceof QTableMetaData)
|
||||
{
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, PrivatePermissionSubType.READ, PrivatePermissionSubType.WRITE);
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, metaDataWithPermissionRules, PrivatePermissionSubType.READ, PrivatePermissionSubType.WRITE);
|
||||
}
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, PrivatePermissionSubType.HAS_ACCESS);
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, metaDataWithPermissionRules, PrivatePermissionSubType.HAS_ACCESS);
|
||||
}
|
||||
case READ_INSERT_EDIT_DELETE_PERMISSIONS:
|
||||
{
|
||||
@ -141,9 +140,9 @@ public class PermissionsHelper
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
if(metaDataWithPermissionRules instanceof QTableMetaData)
|
||||
{
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, TablePermissionSubType.READ, TablePermissionSubType.INSERT, TablePermissionSubType.EDIT, TablePermissionSubType.DELETE);
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, metaDataWithPermissionRules, TablePermissionSubType.READ, TablePermissionSubType.INSERT, TablePermissionSubType.EDIT, TablePermissionSubType.DELETE);
|
||||
}
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, PrivatePermissionSubType.HAS_ACCESS);
|
||||
return getPermissionCheckResult(actionInput, rules, permissionBaseName, metaDataWithPermissionRules, PrivatePermissionSubType.HAS_ACCESS);
|
||||
}
|
||||
default:
|
||||
{
|
||||
@ -164,10 +163,6 @@ public class PermissionsHelper
|
||||
|
||||
|
||||
|
||||
static Map<String, CustomPermissionChecker> customPermissionCheckerMap = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -181,12 +176,7 @@ public class PermissionsHelper
|
||||
/////////////////////////////////////
|
||||
// todo - avoid stack overflows... //
|
||||
/////////////////////////////////////
|
||||
if(!customPermissionCheckerMap.containsKey(effectivePermissionRules.getCustomPermissionChecker().getName()))
|
||||
{
|
||||
CustomPermissionChecker customPermissionChecker = QCodeLoader.getAdHoc(CustomPermissionChecker.class, effectivePermissionRules.getCustomPermissionChecker());
|
||||
customPermissionCheckerMap.put(effectivePermissionRules.getCustomPermissionChecker().getName(), customPermissionChecker);
|
||||
}
|
||||
CustomPermissionChecker customPermissionChecker = customPermissionCheckerMap.get(effectivePermissionRules.getCustomPermissionChecker().getName());
|
||||
CustomPermissionChecker customPermissionChecker = QCodeLoader.getAdHoc(CustomPermissionChecker.class, effectivePermissionRules.getCustomPermissionChecker());
|
||||
customPermissionChecker.checkPermissionsThrowing(actionInput, process);
|
||||
return;
|
||||
}
|
||||
@ -421,11 +411,26 @@ public class PermissionsHelper
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
static PermissionCheckResult getPermissionCheckResult(AbstractActionInput actionInput, QPermissionRules rules, String permissionBaseName, PermissionSubType... permissionSubTypes)
|
||||
static PermissionCheckResult getPermissionCheckResult(AbstractActionInput actionInput, QPermissionRules rules, String permissionBaseName, MetaDataWithPermissionRules metaDataWithPermissionRules, PermissionSubType... permissionSubTypes)
|
||||
{
|
||||
for(PermissionSubType permissionSubType : permissionSubTypes)
|
||||
{
|
||||
PermissionSubType effectivePermissionSubType = getEffectivePermissionSubType(rules, permissionSubType);
|
||||
|
||||
if(rules.getCustomPermissionChecker() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
CustomPermissionChecker customPermissionChecker = QCodeLoader.getAdHoc(CustomPermissionChecker.class, rules.getCustomPermissionChecker());
|
||||
customPermissionChecker.checkPermissionsThrowing(actionInput, metaDataWithPermissionRules);
|
||||
return (PermissionCheckResult.ALLOW);
|
||||
}
|
||||
catch(QPermissionDeniedException e)
|
||||
{
|
||||
return (getPermissionDeniedCheckResult(rules));
|
||||
}
|
||||
}
|
||||
|
||||
if(hasPermission(actionInput.getSession(), permissionBaseName, effectivePermissionSubType))
|
||||
{
|
||||
return (PermissionCheckResult.ALLOW);
|
||||
@ -526,7 +531,7 @@ public class PermissionsHelper
|
||||
|
||||
if(!hasPermission(actionInput.getSession(), permissionBaseName, effectivePermissionSubType))
|
||||
{
|
||||
LOG.debug("Throwing permission denied for: " + getPermissionName(permissionBaseName, effectivePermissionSubType) + " for " + actionInput.getSession().getUser());
|
||||
// LOG.debug("Throwing permission denied for: " + getPermissionName(permissionBaseName, effectivePermissionSubType) + " for " + actionInput.getSession().getUser());
|
||||
throw (new QPermissionDeniedException("Permission denied."));
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeUsage;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppSection;
|
||||
@ -356,7 +357,6 @@ public class QInstanceValidator
|
||||
qInstance.getTables().forEach((tableName, table) ->
|
||||
{
|
||||
assertCondition(Objects.equals(tableName, table.getName()), "Inconsistent naming for table: " + tableName + "/" + table.getName() + ".");
|
||||
validateAppChildHasValidParentAppName(qInstance, table);
|
||||
|
||||
////////////////////////////////////////
|
||||
// validate the backend for the table //
|
||||
@ -465,10 +465,37 @@ public class QInstanceValidator
|
||||
|
||||
prefix = "Table " + table.getName() + " recordSecurityLock (of key type " + securityKeyTypeName + ") ";
|
||||
|
||||
String fieldName = recordSecurityLock.getFieldName();
|
||||
if(assertCondition(StringUtils.hasContent(fieldName), prefix + "is missing a fieldName"))
|
||||
boolean hasAnyBadJoins = false;
|
||||
for(String joinName : CollectionUtils.nonNullList(recordSecurityLock.getJoinNameChain()))
|
||||
{
|
||||
assertCondition(findField(qInstance, table, null, fieldName), prefix + "has an unrecognized fieldName: " + fieldName);
|
||||
if(!assertCondition(qInstance.getJoin(joinName) != null, prefix + "has an unrecognized joinName: " + joinName))
|
||||
{
|
||||
hasAnyBadJoins = true;
|
||||
}
|
||||
}
|
||||
|
||||
String fieldName = recordSecurityLock.getFieldName();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// don't bother trying to validate field names if we know we have a bad join. //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
if(assertCondition(StringUtils.hasContent(fieldName), prefix + "is missing a fieldName") && !hasAnyBadJoins)
|
||||
{
|
||||
List<QueryJoin> joins = new ArrayList<>();
|
||||
for(String joinName : CollectionUtils.nonNullList(recordSecurityLock.getJoinNameChain()))
|
||||
{
|
||||
QJoinMetaData join = qInstance.getJoin(joinName);
|
||||
if(join.getLeftTable().equals(table.getName()))
|
||||
{
|
||||
joins.add(new QueryJoin(join));
|
||||
}
|
||||
else if(join.getRightTable().equals(table.getName()))
|
||||
{
|
||||
joins.add(new QueryJoin(join.flip()));
|
||||
}
|
||||
}
|
||||
|
||||
assertCondition(findField(qInstance, table, joins, fieldName), prefix + "has an unrecognized fieldName: " + fieldName);
|
||||
}
|
||||
|
||||
assertCondition(recordSecurityLock.getNullValueBehavior() != null, prefix + "is missing a nullValueBehavior");
|
||||
@ -960,8 +987,6 @@ public class QInstanceValidator
|
||||
{
|
||||
assertCondition(Objects.equals(processName, process.getName()), "Inconsistent naming for process: " + processName + "/" + process.getName() + ".");
|
||||
|
||||
validateAppChildHasValidParentAppName(qInstance, process);
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// validate the table name for the process //
|
||||
/////////////////////////////////////////////
|
||||
@ -1015,7 +1040,6 @@ public class QInstanceValidator
|
||||
qInstance.getReports().forEach((reportName, report) ->
|
||||
{
|
||||
assertCondition(Objects.equals(reportName, report.getName()), "Inconsistent naming for report: " + reportName + "/" + report.getName() + ".");
|
||||
validateAppChildHasValidParentAppName(qInstance, report);
|
||||
|
||||
////////////////////////////////////////
|
||||
// validate dataSources in the report //
|
||||
@ -1172,6 +1196,7 @@ public class QInstanceValidator
|
||||
{
|
||||
joinTable.getField(fieldNameAfterDot);
|
||||
foundField = true;
|
||||
break;
|
||||
}
|
||||
catch(Exception e2)
|
||||
{
|
||||
@ -1216,7 +1241,10 @@ public class QInstanceValidator
|
||||
Set<String> childNames = new HashSet<>();
|
||||
for(QAppChildMetaData child : app.getChildren())
|
||||
{
|
||||
assertCondition(Objects.equals(appName, child.getParentAppName()), "Child " + child.getName() + " of app " + appName + " does not have its parent app properly set.");
|
||||
if(child instanceof QAppMetaData childApp)
|
||||
{
|
||||
assertCondition(Objects.equals(appName, childApp.getParentAppName()), "Child app " + child.getName() + " of app " + appName + " does not have its parent app properly set.");
|
||||
}
|
||||
assertCondition(!childNames.contains(child.getName()), "App " + appName + " contains more than one child named " + child.getName());
|
||||
childNames.add(child.getName());
|
||||
}
|
||||
@ -1442,7 +1470,7 @@ public class QInstanceValidator
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void validateAppChildHasValidParentAppName(QInstance qInstance, QAppChildMetaData appChild)
|
||||
private void validateAppChildHasValidParentAppName(QInstance qInstance, QAppMetaData appChild)
|
||||
{
|
||||
if(appChild.getParentAppName() != null)
|
||||
{
|
||||
|
@ -28,6 +28,7 @@ import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
@ -76,7 +77,7 @@ public class JoinsContext
|
||||
///////////////////////////////////////////////////////////////
|
||||
for(RecordSecurityLock recordSecurityLock : CollectionUtils.nonNullList(instance.getTable(tableName).getRecordSecurityLocks()))
|
||||
{
|
||||
for(String joinName : CollectionUtils.nonNullList(recordSecurityLock.getJoinChain()))
|
||||
for(String joinName : CollectionUtils.nonNullList(recordSecurityLock.getJoinNameChain()))
|
||||
{
|
||||
if(this.queryJoins.stream().anyMatch(qj -> qj.getJoinMetaData().getName().equals(joinName)))
|
||||
{
|
||||
@ -86,7 +87,12 @@ public class JoinsContext
|
||||
}
|
||||
else
|
||||
{
|
||||
this.queryJoins.add(new QueryJoin().withJoinMetaData(instance.getJoin(joinName)).withType(QueryJoin.Type.INNER)); // todo aliases? probably.
|
||||
QJoinMetaData join = instance.getJoin(joinName);
|
||||
if(tableName.equals(join.getRightTable()))
|
||||
{
|
||||
join = join.flip();
|
||||
}
|
||||
this.queryJoins.add(new QueryJoin().withJoinMetaData(join).withType(QueryJoin.Type.INNER)); // todo aliases? probably.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -300,10 +300,20 @@ public class QJoinMetaData
|
||||
*******************************************************************************/
|
||||
public QJoinMetaData withInferredName()
|
||||
{
|
||||
if(!StringUtils.hasContent(getLeftTable()) || !StringUtils.hasContent(getRightTable()))
|
||||
return (withName(makeInferredJoinName(getLeftTable(), getRightTable())));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static String makeInferredJoinName(String leftTable, String rightTable)
|
||||
{
|
||||
if(!StringUtils.hasContent(leftTable) || !StringUtils.hasContent(rightTable))
|
||||
{
|
||||
throw (new IllegalStateException("Missing either a left or right table name when trying to set inferred name for join"));
|
||||
}
|
||||
return (withName(getLeftTable() + "Join" + StringUtils.ucFirst(getRightTable())));
|
||||
return (leftTable + "Join" + StringUtils.ucFirst(rightTable));
|
||||
}
|
||||
}
|
||||
|
@ -28,16 +28,6 @@ package com.kingsrook.qqq.backend.core.model.metadata.layout;
|
||||
*******************************************************************************/
|
||||
public interface QAppChildMetaData
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
void setParentAppName(String parentAppName);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
String getParentAppName();
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -169,7 +169,11 @@ public class QAppMetaData implements QAppChildMetaData, MetaDataWithPermissionRu
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
this.children.add(child);
|
||||
child.setParentAppName(this.getName());
|
||||
|
||||
if(child instanceof QAppMetaData childApp)
|
||||
{
|
||||
childApp.setParentAppName(this.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -202,7 +206,6 @@ public class QAppMetaData implements QAppChildMetaData, MetaDataWithPermissionRu
|
||||
** Getter for parentAppName
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getParentAppName()
|
||||
{
|
||||
return parentAppName;
|
||||
@ -214,7 +217,6 @@ public class QAppMetaData implements QAppChildMetaData, MetaDataWithPermissionRu
|
||||
** Setter for parentAppName
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void setParentAppName(String parentAppName)
|
||||
{
|
||||
this.parentAppName = parentAppName;
|
||||
|
@ -54,8 +54,7 @@ public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissi
|
||||
private List<QStepMetaData> stepList; // these are the steps that are ran, by-default, in the order they are ran in
|
||||
private Map<String, QStepMetaData> steps; // this is the full map of possible steps
|
||||
|
||||
private String parentAppName;
|
||||
private QIcon icon;
|
||||
private QIcon icon;
|
||||
|
||||
private QScheduleMetaData schedule;
|
||||
|
||||
@ -388,30 +387,6 @@ public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissi
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for parentAppName
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getParentAppName()
|
||||
{
|
||||
return parentAppName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for parentAppName
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void setParentAppName(String parentAppName)
|
||||
{
|
||||
this.parentAppName = parentAppName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for icon
|
||||
**
|
||||
|
@ -48,8 +48,7 @@ public class QReportMetaData implements QAppChildMetaData, MetaDataWithPermissio
|
||||
private List<QReportDataSource> dataSources;
|
||||
private List<QReportView> views;
|
||||
|
||||
private String parentAppName;
|
||||
private QIcon icon;
|
||||
private QIcon icon;
|
||||
|
||||
|
||||
|
||||
@ -304,28 +303,6 @@ public class QReportMetaData implements QAppChildMetaData, MetaDataWithPermissio
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void setParentAppName(String parentAppName)
|
||||
{
|
||||
this.parentAppName = parentAppName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getParentAppName()
|
||||
{
|
||||
return (this.parentAppName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for icon
|
||||
**
|
||||
|
@ -34,7 +34,7 @@ public class RecordSecurityLock
|
||||
{
|
||||
private String securityKeyType;
|
||||
private String fieldName;
|
||||
private List<String> joinChain; // todo - add validation in validator!!
|
||||
private List<String> joinNameChain; // todo - add validation in validator!!
|
||||
private NullValueBehavior nullValueBehavior = NullValueBehavior.DENY;
|
||||
|
||||
|
||||
@ -152,34 +152,34 @@ public class RecordSecurityLock
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for joinChain
|
||||
** Getter for joinNameChain
|
||||
*******************************************************************************/
|
||||
public List<String> getJoinChain()
|
||||
public List<String> getJoinNameChain()
|
||||
{
|
||||
return (this.joinChain);
|
||||
return (this.joinNameChain);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for joinChain
|
||||
** Setter for joinNameChain
|
||||
*******************************************************************************/
|
||||
public void setJoinChain(List<String> joinChain)
|
||||
public void setJoinNameChain(List<String> joinNameChain)
|
||||
{
|
||||
this.joinChain = joinChain;
|
||||
this.joinNameChain = joinNameChain;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for joinChain
|
||||
** Fluent setter for joinNameChain
|
||||
*******************************************************************************/
|
||||
public RecordSecurityLock withJoinChain(List<String> joinChain)
|
||||
public RecordSecurityLock withJoinNameChain(List<String> joinNameChain)
|
||||
{
|
||||
this.joinChain = joinChain;
|
||||
this.joinNameChain = joinNameChain;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -80,8 +80,7 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
|
||||
|
||||
private Map<String, QCodeReference> customizers;
|
||||
|
||||
private String parentAppName;
|
||||
private QIcon icon;
|
||||
private QIcon icon;
|
||||
|
||||
private String recordLabelFormat;
|
||||
private List<String> recordLabelFields;
|
||||
@ -538,30 +537,6 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for parentAppName
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getParentAppName()
|
||||
{
|
||||
return parentAppName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for parentAppName
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void setParentAppName(String parentAppName)
|
||||
{
|
||||
this.parentAppName = parentAppName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for icon
|
||||
**
|
||||
|
@ -242,7 +242,7 @@ class MetaDataActionTest
|
||||
// with several permissions set, we should see some things, and they should have permissions turned on //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
assertEquals(Set.of("person"), result.getTables().keySet());
|
||||
assertEquals(Set.of("increaseBirthdate", "runShapesPersonReport"), result.getProcesses().keySet());
|
||||
assertEquals(Set.of("increaseBirthdate", "runShapesPersonReport", "person.bulkInsert", "person.bulkEdit", "person.bulkDelete"), result.getProcesses().keySet());
|
||||
assertEquals(Set.of("shapesPersonReport", "personJoinShapeReport", "simplePersonReport"), result.getReports().keySet());
|
||||
assertEquals(Set.of("PersonsByCreateDateBarChart"), result.getWidgets().keySet());
|
||||
|
||||
@ -276,7 +276,8 @@ class MetaDataActionTest
|
||||
MetaDataOutput result = new MetaDataAction().execute(input);
|
||||
|
||||
assertEquals(Set.of("person", "personFile", "personMemory"), result.getTables().keySet());
|
||||
assertEquals(Set.of("increaseBirthdate"), result.getProcesses().keySet());
|
||||
|
||||
assertEquals(Set.of("increaseBirthdate", "personFile.bulkInsert", "personFile.bulkEdit", "personFile.bulkDelete", "personMemory.bulkInsert", "personMemory.bulkEdit", "personMemory.bulkDelete"), result.getProcesses().keySet());
|
||||
assertEquals(Set.of(), result.getReports().keySet());
|
||||
assertEquals(Set.of(), result.getWidgets().keySet());
|
||||
|
||||
@ -322,7 +323,7 @@ class MetaDataActionTest
|
||||
MetaDataOutput result = new MetaDataAction().execute(input);
|
||||
|
||||
assertEquals(Set.of("person", "personFile", "personMemory"), result.getTables().keySet());
|
||||
assertEquals(Set.of("increaseBirthdate"), result.getProcesses().keySet());
|
||||
assertEquals(Set.of("increaseBirthdate", "personFile.bulkInsert", "personFile.bulkEdit", "personMemory.bulkDelete"), result.getProcesses().keySet());
|
||||
assertEquals(Set.of(), result.getReports().keySet());
|
||||
assertEquals(Set.of(), result.getWidgets().keySet());
|
||||
|
||||
|
@ -504,8 +504,6 @@ class QInstanceValidatorTest
|
||||
void testChildrenWithBadParentAppName()
|
||||
{
|
||||
String[] reasons = new String[] { "Unrecognized parent app", "does not have its parent app properly set" };
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable(TestUtils.TABLE_NAME_PERSON).setParentAppName("notAnApp"), reasons);
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getProcess(TestUtils.PROCESS_NAME_GREET_PEOPLE).setParentAppName("notAnApp"), reasons);
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getApp(TestUtils.APP_NAME_GREETINGS).setParentAppName("notAnApp"), reasons);
|
||||
}
|
||||
|
||||
|
@ -310,11 +310,11 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
{
|
||||
String whereClauseWithoutSecurity = makeWhereClauseWithoutSecurity(instance, table, joinsContext, filter, params);
|
||||
QQueryFilter securityFilter = getSecurityFilter(instance, session, table, joinsContext);
|
||||
if(securityFilter == null || CollectionUtils.nullSafeIsEmpty(securityFilter.getCriteria()))
|
||||
if(!securityFilter.hasAnyCriteria())
|
||||
{
|
||||
return (whereClauseWithoutSecurity);
|
||||
}
|
||||
String securityWhereClause = getSqlWhereStringAndPopulateParamsListFromNonNestedFilter(instance, table, joinsContext, securityFilter.getCriteria(), QQueryFilter.BooleanOperator.AND, params);
|
||||
String securityWhereClause = makeWhereClauseWithoutSecurity(instance, table, joinsContext, securityFilter, params);
|
||||
return ("(" + whereClauseWithoutSecurity + ") AND (" + securityWhereClause + ")");
|
||||
}
|
||||
|
||||
@ -367,14 +367,14 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
*******************************************************************************/
|
||||
private QQueryFilter getSecurityFilter(QInstance instance, QSession session, QTableMetaData table, JoinsContext joinsContext)
|
||||
{
|
||||
QQueryFilter newFilter = new QQueryFilter();
|
||||
newFilter.setBooleanOperator(QQueryFilter.BooleanOperator.AND);
|
||||
List<QFilterCriteria> securityCriteria = new ArrayList<>();
|
||||
newFilter.setCriteria(securityCriteria);
|
||||
QQueryFilter securityFilter = new QQueryFilter();
|
||||
securityFilter.setBooleanOperator(QQueryFilter.BooleanOperator.AND);
|
||||
|
||||
for(RecordSecurityLock recordSecurityLock : CollectionUtils.nonNullList(table.getRecordSecurityLocks()))
|
||||
{
|
||||
addCriteriaForRecordSecurityLock(instance, session, table, securityCriteria, recordSecurityLock, joinsContext, table.getName());
|
||||
// todo - uh, if it's a RIGHT (or FULL) join, then, this should be isOuter = true, right?
|
||||
boolean isOuter = false;
|
||||
addSubFilterForRecordSecurityLock(instance, session, table, securityFilter, recordSecurityLock, joinsContext, table.getName(), isOuter);
|
||||
}
|
||||
|
||||
for(QueryJoin queryJoin : CollectionUtils.nonNullList(joinsContext.getQueryJoins()))
|
||||
@ -382,11 +382,12 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
QTableMetaData joinTable = instance.getTable(queryJoin.getJoinTable());
|
||||
for(RecordSecurityLock recordSecurityLock : CollectionUtils.nonNullList(joinTable.getRecordSecurityLocks()))
|
||||
{
|
||||
addCriteriaForRecordSecurityLock(instance, session, joinTable, securityCriteria, recordSecurityLock, joinsContext, queryJoin.getJoinTableOrItsAlias());
|
||||
boolean isOuter = queryJoin.getType().equals(QueryJoin.Type.LEFT); // todo full?
|
||||
addSubFilterForRecordSecurityLock(instance, session, joinTable, securityFilter, recordSecurityLock, joinsContext, queryJoin.getJoinTableOrItsAlias(), isOuter);
|
||||
}
|
||||
}
|
||||
|
||||
return (newFilter);
|
||||
return (securityFilter);
|
||||
}
|
||||
|
||||
|
||||
@ -394,7 +395,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void addCriteriaForRecordSecurityLock(QInstance instance, QSession session, QTableMetaData table, List<QFilterCriteria> securityCriteria, RecordSecurityLock recordSecurityLock, JoinsContext joinsContext, String tableNameOrAlias)
|
||||
private static void addSubFilterForRecordSecurityLock(QInstance instance, QSession session, QTableMetaData table, QQueryFilter securityFilter, RecordSecurityLock recordSecurityLock, JoinsContext joinsContext, String tableNameOrAlias, boolean isOuter)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// check if the key type has an all-access key, and if so, if it's set to true for the current user/session //
|
||||
@ -411,9 +412,12 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
}
|
||||
}
|
||||
|
||||
if(CollectionUtils.nullSafeHasContents(recordSecurityLock.getJoinChain()))
|
||||
String fieldName = tableNameOrAlias + "." + recordSecurityLock.getFieldName();
|
||||
String fieldNameWithoutTablePrefix = recordSecurityLock.getFieldName().replaceFirst(".*\\.", "");
|
||||
String fieldNameTablePrefix = recordSecurityLock.getFieldName().replaceFirst("\\..*", "");
|
||||
if(CollectionUtils.nullSafeHasContents(recordSecurityLock.getJoinNameChain()))
|
||||
{
|
||||
for(String joinName : recordSecurityLock.getJoinChain())
|
||||
for(String joinName : recordSecurityLock.getJoinNameChain())
|
||||
{
|
||||
QJoinMetaData joinMetaData = instance.getJoin(joinName);
|
||||
|
||||
@ -433,16 +437,27 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
throw (new RuntimeException("Could not find joinMetaData for recordSecurityLock with joinChain member [" + joinName + "]"));
|
||||
}
|
||||
|
||||
table = instance.getTable(joinMetaData.getRightTable());
|
||||
if(fieldNameTablePrefix.equals(joinMetaData.getLeftTable()))
|
||||
{
|
||||
table = instance.getTable(joinMetaData.getLeftTable());
|
||||
}
|
||||
else
|
||||
{
|
||||
table = instance.getTable(joinMetaData.getRightTable());
|
||||
}
|
||||
|
||||
tableNameOrAlias = table.getName();
|
||||
fieldName = tableNameOrAlias + "." + fieldNameWithoutTablePrefix;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// else - get the key values from the session and decide what kind of criterion to build //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
List<Serializable> securityKeyValues = session.getSecurityKeyValues(recordSecurityLock.getSecurityKeyType(), table.getField(recordSecurityLock.getFieldName()).getType());
|
||||
String fieldName = tableNameOrAlias + "." + recordSecurityLock.getFieldName();
|
||||
QQueryFilter lockFilter = new QQueryFilter();
|
||||
List<QFilterCriteria> lockCriteria = new ArrayList<>();
|
||||
lockFilter.setCriteria(lockCriteria);
|
||||
List<Serializable> securityKeyValues = session.getSecurityKeyValues(recordSecurityLock.getSecurityKeyType(), table.getField(fieldNameWithoutTablePrefix).getType());
|
||||
if(CollectionUtils.nullSafeIsEmpty(securityKeyValues))
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -450,7 +465,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(RecordSecurityLock.NullValueBehavior.ALLOW.equals(recordSecurityLock.getNullValueBehavior()))
|
||||
{
|
||||
securityCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_BLANK));
|
||||
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_BLANK));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -458,7 +473,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
// else, if no user/session values, and null-value behavior is deny, then setup a FALSE condition, to allow no rows. //
|
||||
// todo - make some explicit contradiction here - maybe even avoid running the whole query - as you're not allowed ANY records //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
securityCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IN, Collections.emptyList()));
|
||||
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IN, Collections.emptyList()));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -469,13 +484,26 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(RecordSecurityLock.NullValueBehavior.ALLOW.equals(recordSecurityLock.getNullValueBehavior()))
|
||||
{
|
||||
securityCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_NULL_OR_IN, securityKeyValues));
|
||||
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_NULL_OR_IN, securityKeyValues));
|
||||
}
|
||||
else
|
||||
{
|
||||
securityCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IN, securityKeyValues));
|
||||
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IN, securityKeyValues));
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if this field is on the outer side of an outer join, then if we do a straight filter on it, then we're basically //
|
||||
// nullifying the outer join... so for an outer join use-case, OR the security field criteria with a primary-key IS NULL //
|
||||
// which will make missing rows from the join be found. //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(isOuter)
|
||||
{
|
||||
lockFilter.setBooleanOperator(QQueryFilter.BooleanOperator.OR);
|
||||
lockFilter.addCriteria(new QFilterCriteria(tableNameOrAlias + "." + table.getPrimaryKeyField(), QCriteriaOperator.IS_BLANK));
|
||||
}
|
||||
|
||||
securityFilter.addSubFilter(lockFilter);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1287,8 +1287,8 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
||||
qInstance.getTable(TestUtils.TABLE_NAME_ORDER).getRecordSecurityLocks().clear();
|
||||
qInstance.getTable(TestUtils.TABLE_NAME_ORDER).withRecordSecurityLock(new RecordSecurityLock()
|
||||
.withSecurityKeyType(TestUtils.TABLE_NAME_STORE)
|
||||
.withJoinChain(List.of("orderJoinStore"))
|
||||
.withFieldName("id"));
|
||||
.withJoinNameChain(List.of("orderJoinStore"))
|
||||
.withFieldName("store.id"));
|
||||
|
||||
queryInput.setFilter(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.BETWEEN, List.of(2, 7))));
|
||||
queryInput.setSession(new QSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_STORE_ALL_ACCESS, true));
|
||||
|
@ -5,6 +5,11 @@
|
||||
## Reset the version of all qqq deps in a given pom to the current snapshot.
|
||||
############################################################################
|
||||
|
||||
if [ ! -e pom.xml ]; then
|
||||
echo "Error: $0 Must be ran in a directory with a pom.xml"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
CURRENT_VERSION="$(cat $QQQ_DEV_TOOLS_DIR/CURRENT-SNAPSHOT-VERSION)"
|
||||
MODULE_LIST_FILE=$QQQ_DEV_TOOLS_DIR/MODULE_LIST
|
||||
|
||||
|
@ -5,6 +5,11 @@
|
||||
## Set the version of all qqq deps in a given pom to the latest snapshot.
|
||||
############################################################################
|
||||
|
||||
if [ ! -e pom.xml ]; then
|
||||
echo "Error: $0 Must be ran in a directory with a pom.xml"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
CURRENT_VERSION="$(cat $QQQ_DEV_TOOLS_DIR/CURRENT-SNAPSHOT-VERSION)"
|
||||
MODULE_LIST_FILE=$QQQ_DEV_TOOLS_DIR/MODULE_LIST
|
||||
|
||||
|
Reference in New Issue
Block a user